首页 文章

派生特征会导致意外的编译器错误,但手动实现会起作用

提问于
浏览
13

这段代码(playground):

#[derive(Clone)]
struct Foo<'a, T: 'a> {
    t: &'a T,
}

fn bar<'a, T>(foo: Foo<'a, T>) {
    foo.clone();
}

......不编译:

error: no method named `clone` found for type `Foo<'a, T>` in the current scope
  --> <anon>:7:9
   |>
16 |>     foo.clone();
   |>         ^^^^^
note: the method `clone` exists but the following trait bounds were not satisfied: `T : std::clone::Clone`
help: items from traits can only be used if the trait is implemented and in scope; the following trait defines an item `clone`, perhaps you need to implement it:
help: candidate #1: `std::clone::Clone`

无论如何,添加 use std::clone::Clone; 不是't change anything, as it'已经在前奏中了 .

当我删除 #[derive(Clone)] 并为 Foo 手动实现 Clone 时,它 compiles as expected

impl<'a, T> Clone for Foo<'a, T> {
    fn clone(&self) -> Self {
        Foo {
            t: self.t,
        }
    }
}

这里发生了什么?

  • #[derive()] -impls与手动之间有区别吗?

  • 这是编译器错误吗?

  • 我没想到的其他东西?

2 回答

  • 22

    答案隐藏在错误消息中:

    方法克隆存在,但不满足以下特征边界:T:std :: clone :: Clone

    当您派生 Clone (以及许多其他自动派生类型)时,它会在 all 泛型类型上添加 Clone 绑定 . 使用 rustc -Z unstable-options --pretty=expanded ,我们可以看到它变成了什么:

    impl <'a, T: ::std::clone::Clone + 'a> ::std::clone::Clone for Foo<'a, T> {
        #[inline]
        fn clone(&self) -> Foo<'a, T> {
            match *self {
                Foo { t: ref __self_0_0 } =>
                Foo{t: ::std::clone::Clone::clone(&(*__self_0_0)),},
            }
        }
    }
    

    在这种情况下,不需要绑定,因为泛型类型在引用后面 .

    目前,您需要自己实施 Clone . There's a Rust issue for this,但这是一个相对罕见的解决方案 .

  • 4

    如果您明确标记 T 应该实现 Clone ,那么您的示例将派生 Clone 没有任何问题,如下所示:

    #[derive(Clone)]
    struct Foo<'a, T: 'a> {
        t: &'a T,
    }
    
    fn bar<'a, T: Clone>(foo: Foo<'a, T>) {
        foo.clone();
    }
    

    Playground link

    你可以避免明确地指定绑定似乎很不寻常,但Shepmaster的答案似乎暗示编译器隐式插入它,所以我的建议在功能上是相同的 .

相关问题