派生特征会导致意外的编译器错误,但手动实现有效
Deriving a trait results in unexpected compiler error, but the manual implementation works
此代码(playground):
#[derive(Clone)]
struct Foo<'a, T: 'a> {
t: &'a T,
}
fn bar<'a, T>(foo: Foo<'a, T>) {
foo.clone();
}
...不编译:
error[E0599]: no method named `clone` found for struct `Foo<'a, T>` in the current scope
--> src/main.rs:16:9
|
3 | struct Foo<'a, T: 'a> {
| ---------------------
| |
| method `clone` not found for this
| doesn't satisfy `Foo<'_, T>: std::clone::Clone`
...
16 | foo.clone();
| ^^^^^ method not found in `Foo<'a, T>`
|
= note: the method `clone` exists but the following trait bounds were not satisfied:
`T: std::clone::Clone`
which is required by `Foo<'_, T>: std::clone::Clone`
help: consider restricting the type parameter to satisfy the trait bound
|
3 | struct Foo<'a, T: 'a> where T: std::clone::Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
添加 use std::clone::Clone;
不会改变任何东西,因为它已经在前奏中了。
当我删除 #[derive(Clone)]
并为 Foo
手动实施 Clone
时,它 按预期编译 !
impl<'a, T> Clone for Foo<'a, T> {
fn clone(&self) -> Self {
Foo {
t: self.t,
}
}
}
这是怎么回事?
#[derive()]
-impls 和手动的有区别吗?
- 这是编译器错误吗?
- 还有什么我没有想到的?
答案隐藏在错误信息中:
= note: the method `clone` exists but the following trait bounds were not satisfied:
`T: std::clone::Clone`
which is required by `Foo<'_, 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)),},
}
}
}
在这种情况下,不需要绑定,因为泛型类型在引用后面。
现在,您需要自己实施 Clone
。 There's a Rust issue for this,但这是一个相对罕见的解决方法。
如果您明确标记 T
应实现 Clone
,您的示例将毫无问题地派生 Clone
,如下所示:
#[derive(Clone)]
struct Foo<'a, T: 'a> {
t: &'a T,
}
fn bar<'a, T: Clone>(foo: Foo<'a, T>) {
foo.clone();
}
您可以避免明确指定边界似乎很不寻常,但 Shepmaster 的回答似乎暗示编译器会隐式插入它,因此我的建议在功能上是相同的。
此代码(playground):
#[derive(Clone)]
struct Foo<'a, T: 'a> {
t: &'a T,
}
fn bar<'a, T>(foo: Foo<'a, T>) {
foo.clone();
}
...不编译:
error[E0599]: no method named `clone` found for struct `Foo<'a, T>` in the current scope
--> src/main.rs:16:9
|
3 | struct Foo<'a, T: 'a> {
| ---------------------
| |
| method `clone` not found for this
| doesn't satisfy `Foo<'_, T>: std::clone::Clone`
...
16 | foo.clone();
| ^^^^^ method not found in `Foo<'a, T>`
|
= note: the method `clone` exists but the following trait bounds were not satisfied:
`T: std::clone::Clone`
which is required by `Foo<'_, T>: std::clone::Clone`
help: consider restricting the type parameter to satisfy the trait bound
|
3 | struct Foo<'a, T: 'a> where T: std::clone::Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
添加 use std::clone::Clone;
不会改变任何东西,因为它已经在前奏中了。
当我删除 #[derive(Clone)]
并为 Foo
手动实施 Clone
时,它 按预期编译 !
impl<'a, T> Clone for Foo<'a, T> {
fn clone(&self) -> Self {
Foo {
t: self.t,
}
}
}
这是怎么回事?
#[derive()]
-impls 和手动的有区别吗?- 这是编译器错误吗?
- 还有什么我没有想到的?
答案隐藏在错误信息中:
= note: the method `clone` exists but the following trait bounds were not satisfied: `T: std::clone::Clone` which is required by `Foo<'_, 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)),},
}
}
}
在这种情况下,不需要绑定,因为泛型类型在引用后面。
现在,您需要自己实施 Clone
。 There's a Rust issue for this,但这是一个相对罕见的解决方法。
如果您明确标记 T
应实现 Clone
,您的示例将毫无问题地派生 Clone
,如下所示:
#[derive(Clone)]
struct Foo<'a, T: 'a> {
t: &'a T,
}
fn bar<'a, T: Clone>(foo: Foo<'a, T>) {
foo.clone();
}
您可以避免明确指定边界似乎很不寻常,但 Shepmaster 的回答似乎暗示编译器会隐式插入它,因此我的建议在功能上是相同的。