在下面的示例代码中,特征Foo要求关联的类型X实现Clone特征.

do_it函数签名中使用impl Foo<X = Baz>语法时,cargo check不会抱怨Baz没有实现Clone特征.

然而,在impl Foo for Bar区,确实有cargo check人抱怨这个问题.

我本以为会有impl Foo<X = Baz>人以同样的方式抱怨.

trait Foo {
    type X: Clone;
}

struct Bar;

struct Baz;

impl Foo for Bar {
    type X = Baz; // <- complains Baz does not impl Clone trait
}

fn do_it(foo: impl Foo<X = Baz>) {} // <- does not complain

如果X是泛型参数,则情况并非如此.在这种情况下,cargo check表示foo: impl Foo<Bar>不满足Clone性状界限

trait Foo<X>
where
    X: Clone,
{
}

struct Bar;

struct Baz;

fn do_it(foo: impl Foo<Baz>) {} // <- complains Baz does not impl Clone trait

这是故意的行为吗?如果是的话,原因是什么?

推荐答案

这是在the RFC introducing associated types节中用一句简短的话描述的:

关联类型上的BOUNDSWHERE_CLAUSE对于特征的实现者是obligations,对于特征的用户是assumptions:

trait Graph {
    type N: Show + Hash;
    type E: Show + Hash;
    ...
}

impl Graph for MyGraph {
    // Both MyNode and MyEdge must implement Show and Hash
    type N = MyNode;
    type E = MyEdge;
    ...
}

fn print_nodes<G: Graph>(g: &G) {
    // here, can assume G::N implements Show
    ...
}

这意味着负责证明边界成立的人不是特征的使用者(在您的示例中为do_it()),而是特征的实现者.这与特征的一般参数形成对比,在一般参数中,证明义务由用户承担.

当您查看它时,差异应该是显而易见的:对于泛型参数,类型是外来的,并且在特征实现中是未知的,因此它必须假设边界漏洞.另一方面,特征的用户具有针对它们的具体类型(即使它们本身是泛型的,从特征的Angular 来看,它们仍然是具体类型),因此它应该证明界限是成立的.相比之下,对于关联类型,情况有所不同:实现者知props 体类型,而用户假定为泛型类型(即使像您的代码一样,它将它们限制为特定类型,但在一般情况下它仍然是未知的).

请注意,关联类型上有where bounds(type Foo where Self::Foo: Clone),它们是通过泛型关联类型引入的(是的,我知道我链接的RFC带来了它们,但就我所知,它们并没有实现,并最终作为具有不同语义的Gat的一部分实现),这个故事再次不同于普通的关联类型界限:用户也必须证明它们(我认为两者都需要证明,但我不确定).这是因为它们被预期用于关联类型上的泛型参数,因此它们类似于特征上的泛型参数,或其中的WHERE子句.

Rust相关问答推荐

将大小为零的类型实例存储到空指针中

值为可变对象的不可变HashMap

为什么允许我们将可变引用转换为不可变引用?

在Rust中有没有办法在没有UB的情况下在指针和U64之间进行转换?

如何点击()迭代器?

如何用Axum/Tower压缩Html内容?

像这样的铁 rust 图案除了‘选项’之外,还有其他 Select 吗?

Rust&;Tokio:如何处理更多的信号,而不仅仅是SIGINT,即SIGQUE?

如何修复&q;无法返回引用函数参数的值在异步规则中返回引用当前函数&q;拥有的数据的值?

我如何使用AWS SDK for Rust获取我承担的角色的凭据?

为什么在 Allocator API 中 allocate() 使用 `[u8]` 而 deallocate 使用 `u8` ?

我可以解构self 参数吗?

Rust与_有何区别?

简单 TCP 服务器的连接由对等重置错误,mio 负载较小

std::vector::shrink_to_fit 如何在 Rust 中工作?

在每个循环迭代中删除borrow

发生移动是因为 `data` 的类型为 `Vec`,它没有实现 `Copy` 特性

如何使用 rust bindgen 生成的 std_vector

在 Rust 中获得准确时间的正确方法?

基于名称是否存在的条件编译