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

时间:2016-09-09 15:29:57

标签: rust clone

此代码(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()] - impls和手动之间是否存在差异?
  • 这是编译错误吗?
  • 我还没有想到的其他东西?

2 个答案:

答案 0 :(得分:22)

答案隐藏在错误消息中:

  

方法clone存在,但不满足以下特征限制:T : std::clone::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)),},
        }
    }
}

this 的情况下,不需要绑定,因为泛型类型在引用后面。

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

答案 1 :(得分:4)

如果您明确标记Clone应该实施T,那么您的示例将毫无问题地派生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的答案似乎暗示编译器会隐式插入它,所以我的建议在功能上是相同的。