代码之家  ›  专栏  ›  技术社区  ›  rodrigo

#[派生(克隆)]

  •  2
  • rodrigo  · 技术社区  · 7 年前

    此代码( 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; 什么都没变,反正已经在序曲里了。

    当我移除 #[derive(Clone)] 手动执行 Clone 对于 Foo ,它 按预期编译 !

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

    这是怎么回事?

    • 有区别吗 #[derive()] -简易和手动的?
    • 这是编译器错误吗?
    • 还有什么我没想到的?
    0 回复  |  直到 9 年前
        1
  •  27
  •   Shepmaster Tim Diekmann    9 年前

    答案隐藏在错误消息中:

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

    当你得到 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)),},
            }
        }
    }
    

    case,不需要绑定,因为泛型类型位于引用后面。

    现在,您需要实现 克隆 你自己。 There's a Rust issue for this ,但这是一个相对罕见的情况下,有一个变通办法。

        2
  •  4
  •   Aurora0001    9 年前

    你的例子将衍生 Clone 如果你明确的标记 T 应该执行 克隆 ,就像这样:

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

    ( Playground link )

    您可以避免显式地指定绑定,这似乎不寻常,但是Shepmaster的回答似乎表明编译器隐式地插入了它,所以我的建议在功能上是相同的。

    推荐文章