我对为
Ord
和类似特征的派生实现生成的约束有点困惑。
我注意到,如果
Ord
不是 PhantomData<T>
,则不可能为包含 T
的结构派生 Ord
,即使 PhantomData<T>
也实现了 Ord
,如果 T
没有实现。
例如以下示例无法编译:
use core::marker::PhantomData;
#[derive(PartialEq, Eq, PartialOrd, Ord)]
struct NewPhantomData<T>(PhantomData<T>);
fn needs_ord<T>(_b : T) where T : Ord{ todo!() }
struct TypeWithoutOrd{}
fn foo(){
let a : NewPhantomData<u32> =
NewPhantomData(PhantomData::default());
let b : PhantomData<TypeWithoutOrd> = PhantomData::default();
let c : NewPhantomData<TypeWithoutOrd> =
NewPhantomData(PhantomData::default());
needs_ord(a); //works
needs_ord(b); //works too
needs_ord(c); //does not work
}
(游乐场)
扩展的宏使其无法编译的原因显而易见:
impl<T: ::core::cmp::Ord> ::core::cmp::Ord for NewPhantomData<T> {
#[inline]
fn cmp(&self, other: &NewPhantomData<T>) -> ::core::cmp::Ordering {
::core::cmp::Ord::cmp(&self.0, &other.0)
}
}
然而,令我困惑的是派生实现的特征界限。我本来希望边界看起来像这样:
impl<T> ::core::cmp::Ord for NewPhantomData<T> where PhantomData<T> : ::core::cmp::Ord {
#[inline]
fn cmp(&self, other: &NewPhantomData<T>) -> ::core::cmp::Ordering {
::core::cmp::Ord::cmp(&self.0, &other.0)
}
}
(游乐场)
或者,换句话说,我期望结构体字段类型上的特征绑定,而不是直接绑定到泛型参数。
以这种方式生成边界的原因是什么?这是一个错误吗?
这有一个大问题:周期。
结构体的预期派生边界如下所示:
#[derive(Clone)]
struct List<T> {
data: T,
next: Option<Box<List<T>>>,
}
将包括绑定的
Option<Box<List<T>>>: Clone
,以及类似的循环当前处理不正确。
让它发挥作用是可能的,但很棘手。出错将会对稳健性产生影响。据我了解,当前的特征求解器也非常困难(尽管下一代特征求解器会让它变得更容易)。即使我们修复了这个问题,现在更改它也是一个重大更改,因为人们可以依赖比需要更严格的边界,以便不暴露实现细节(字段的类型是什么)。
仍然希望所谓的“完美派生”能够正确地获得这些边界,并且可能会在未来的某个时候实现。