派生特性会导致意外的编译器错误,但手动实现工作
这个代码( 操场 ):
#[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和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相同。