【问题标题】:Type does not implement Copy error when using supertrait of Copy in an enum在枚举中使用 Copy 的超特征时,类型未实现 Copy 错误
【发布时间】:2021-04-25 08:50:25
【问题描述】:

我是 Rust 特征的新手,所以这可能是由于对超特征、dyn 或其他任何东西的误解。我正在尝试在枚举中使用特征对象:

  • 将特征绑定在可用于枚举的此元素的具体类型上
  • 确保枚举仍然可以派生Copy

最小的例子(在 Rust playground 上编译失败并出现相关错误)是:

#[derive(Copy)]
enum Foo {
    A,
    B(dyn MyTraitWhichIsCopy),
}

trait MyTraitWhichIsCopy: Copy {}

错误是:

error[E0204]: the trait `Copy` may not be implemented for this type
 --> src/lib.rs:1:10
  |
1 | #[derive(Copy)]
  |          ^^^^
...
4 |     B(dyn MyTraitWhichIsCopy),
  |       ---------------------- this field does not implement `Copy`
  |
  = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error

For more information about this error, try `rustc --explain E0204`.

在调用 rustc --explain E0204 之后,我注意到以下内容,这可能是我遇到问题的地方:

The `Copy` trait is implemented by default only on primitive types. If your
type only contains primitive types, you'll be able to implement `Copy` on it.
Otherwise, it won't be possible.

有没有办法完成我想做的事情?

【问题讨论】:

    标签: rust trait-objects


    【解决方案1】:

    给定的代码有几个问题。

    1. 特征 Clone 不是对象安全的,因为方法 clone 引用原始 self 类型,通过 dyn 抽象是未知的。你的特质有一个超级特质CopyCopy有一个超级特质Clone,因此你的特质不是对象安全的,这意味着它不能用作特质对象,也称为“dyn特质”。

    2. Trait 对象是?Sized,这意味着它是一个动态大小的类型(DST,其大小在编译时未知),不能用作枚举字段,因为它也使枚举类型为?Sized。在大多数情况下,DST 只能通过引用来持有,实际上拥有时是 Box<dyn Trait>,否则是 &dyn Trait&mut dyn Trait

    3. Copy 需要超级特征Clone,这意味着“任何实现Copy 的类型都必须实现Clone”。所以当我们希望我们的自定义类型实现Copy时,我们应该首先实现Clone

    结论:通过 trait 对象来约束类型实现CopyClone 是不可能的,你必须使用Box 来保存你的trait 对象,并且使用手动定义的克隆而不是标准克隆 trait 并为装箱的 trait 对象实现克隆:

    trait MyTrait {
        fn clone_dyn(&self) -> Box<dyn MyTrait>;
    }
    
    #[derive(Clone)]
    struct MyImpl;
    
    impl MyTrait for MyImpl {
        fn clone_dyn(&self) -> Box<dyn MyTrait> {
            Box::new(self.clone())
        }
    }
    
    impl Clone for Box<dyn MyTrait> {
        fn clone(&self) -> Self {
            self.clone_dyn()
        }
    }
    
    #[derive(Clone)]
    enum Foo {
        A,
        B(Box<dyn MyTrait>),
    }
    

    【讨论】:

    【解决方案2】:

    您可以使用受您的 trait 约束的泛型类型。另请注意,您还需要Clone 才能拥有Copy

    #[derive(Clone, Copy)]
    enum Foo<T: MyTraitWhichIsCopy> {
        A,
        B(T),
    }
    
    trait MyTraitWhichIsCopy: Copy {}
    

    Playground

    【讨论】:

    • 谢谢 - 我认为我省略了另一个隐含的要求 - 你最终不会得到单独的枚举实例,具体取决于你声明它的类型。因此,我认为 Alsein 的答案更接近我的问题。
    猜你喜欢
    • 2015-09-19
    • 2016-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-01
    • 1970-01-01
    • 2016-11-08
    相关资源
    最近更新 更多