对派生的 `Eq`、`Ord` 等实现的自动生成特征约束

问题描述 投票:0回答:1

我对为

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)
    }
}

(游乐场)

或者,换句话说,我期望结构体字段类型上的特征绑定,而不是直接绑定到泛型参数。

以这种方式生成边界的原因是什么?这是一个错误吗?

generics rust traits
1个回答
1
投票

这有一个大问题:周期。

结构体的预期派生边界如下所示:

#[derive(Clone)]
struct List<T> {
    data: T,
    next: Option<Box<List<T>>>,
}

将包括绑定的

Option<Box<List<T>>>: Clone
,以及类似的循环当前处理不正确

让它发挥作用是可能的,但很棘手。出错将会对稳健性产生影响。据我了解,当前的特征求解器也非常困难(尽管下一代特征求解器会让它变得更容易)。

即使我们修复了这个问题,现在更改它也是一个重大更改,因为人们可以依赖比需要更严格的边界,以便不暴露实现细节(字段的类型是什么)。

仍然希望所谓的“完美派生”能够正确地获得这些边界,并且可能会在未来的某个时候实现。

© www.soinside.com 2019 - 2024. All rights reserved.