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

这个代码( 操场 ):

#[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)]并手动实现CloneFoo ,它按预期编译

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

这里发生了什么?

  • #[derive()] -impls和manual之间有区别吗?
  • 这是一个编译器错误?
  • 还有什么我没有想到的?

答案隐藏在错误信息中:

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

当您派生Clone (以及其他许多自动派生types)时,它会为所有通用types添加一个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)),}, } } } 

这种情况下,不需要边界,因为genericstypes位于引用之后。

目前,您需要Clone实施Clone 。 这里有一个Rust问题 ,但是解决方法是相当less见的情况。

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

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

( 游乐场链接 )

似乎不寻常的是,你可以避免明确指定边界,但Shepmaster的答案似乎暗示编译器隐式插入它,所以我的build议是function相同。