rust '#[derive(Clone)]'似乎错误地强制泛型成为'Clone'

dgsult0t  于 2022-11-12  发布在  其他
关注(0)|答案(2)|浏览(221)

看起来在派生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

vlurs2pr

vlurs2pr1#

这并不是一个编译器错误,因为它是一个documented behavior,尽管人们可能会觉得它很奇怪。编译器在派生时会自动向泛型类型添加约束,即使这些约束在实现中实际上并不需要。例如,为B<T>派生Clone只会实现Clone for B<T>,其中T: Clone、即使不管T是否是Clone都可能实现这一点。
因此,就目前而言(也许编译器将来会更聪明地处理这些情况),是的,这是必须手动实现的情况之一。

owfi6suc

owfi6suc2#

如果您不介意使用smallo依赖项,则可以使用derivative crate来避免手动实现的繁琐1:


# [derive(Derivative)]

# [derivative(Clone(bound = ""))]

struct B<T>(Arc<T>);

Playground
1对于一个小的结构体来说,这种单调乏味的工作并不是那么糟糕,但是对于一个有很多变体的enum来说,实现会变得相当大。

相关问题