看起来在派生Clone
时,Rust将Clone
特征需求转发给不需要该特征的泛型,就像它们被 Package 在Arc
中一样。
我是否误解了Clone
的工作原理,或者这是一个编译器错误?
考虑以下代码,其中a.clone()
工作,但b.clone()
不工作。还要注意,如果没有b.clone()
调用,代码编译良好,表明#[derive(Clone)]
工作。
第一个
当我对宏执行expand操作时,我看到了以下生成的代码:
# ![feature(prelude_import)]
# [prelude_import]
use std::prelude::rust_2018::*;
# [macro_use]
extern crate std;
use std::sync::Arc;
struct Unclonable {}
struct A<T>(Arc<T>);
impl<T> Clone for A<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
struct B<T>(Arc<T>);
# [automatically_derived]
# [allow(unused_qualifications)]
impl<T: ::core::clone::Clone> ::core::clone::Clone for B<T> {
#[inline]
fn clone(&self) -> B<T> {
match *self {
B(ref __self_0_0) => B(::core::clone::Clone::clone(&(*__self_0_0))),
}
}
}
fn main() {
let a = A(Arc::new(Unclonable {}));
let b = B(Arc::new(Unclonable {}));
a.clone();
b.clone();
}
这是怎么回事?为什么Rust编译器要添加<T: ::core::clone::Clone>
??
或者,这只是其中一种情况,其中预期的方式是手动实现Clone
?
2条答案
按热度按时间vlurs2pr1#
这并不是一个编译器错误,因为它是一个documented behavior,尽管人们可能会觉得它很奇怪。编译器在派生时会自动向泛型类型添加约束,即使这些约束在实现中实际上并不需要。例如,为
B<T>
派生Clone
只会实现Clone for B<T>
,其中T: Clone
、即使不管T
是否是Clone
都可能实现这一点。因此,就目前而言(也许编译器将来会更聪明地处理这些情况),是的,这是必须手动实现的情况之一。
owfi6suc2#
如果您不介意使用smallo依赖项,则可以使用
derivative
crate来避免手动实现的繁琐1:Playground
1对于一个小的结构体来说,这种单调乏味的工作并不是那么糟糕,但是对于一个有很多变体的
enum
来说,实现会变得相当大。