Reputation: 1177
I'm new to Rust traits, so this could be due to a misunderstanding of supertraits, dyn
or anything else. I'm trying to use a trait object in an enum to:
Copy
The minimal example (which fails to compile on Rust playground with the relevant error) is:
#[derive(Copy)]
enum Foo {
A,
B(dyn MyTraitWhichIsCopy),
}
trait MyTraitWhichIsCopy: Copy {}
The error is:
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`.
After invoking rustc --explain E0204
I noticed the following, which might be where I'm hitting problems:
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.
Is there a way to accomplish what I'm trying to do?
Upvotes: 1
Views: 1768
Reputation: 4775
There are several problems in the given code.
The trait Clone
is not object-safe because the method clone
refers to the raw self type, which is unknown through the dyn
abstraction. Your trait has a super trait Copy
and Copy
has a super trait Clone
, therefore your trait is not object-safe, which means it cannot be used as a trait object, which is also known as "dyn
trait".
Trait object is ?Sized
which means it is a dynamic sized type (DST, whose size is unknown at compile time) that cannot be used as a enum field because it also makes the enum type ?Sized
. In most cases, DST can only be held through reference, practically Box<dyn Trait>
when owned, otherwise &dyn Trait
or &mut dyn Trait
.
Copy
requires super trait Clone
, which means "any type that implements Copy
must implement Clone
". So when we wish our custom type to implement Copy
, we should implement Clone
first.
Conclusion: It is impossible to constraint a type to implement Copy
or Clone
through a trait object, and you must use a Box
to hold your trait object, and use a manually defined clone instead of the standard clone trait and implement clone for the boxed trait object:
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>),
}
Upvotes: 5
Reputation: 42708
You can use a generic type bound by your trait. Also notice that you need Clone
to have Copy
too:
#[derive(Clone, Copy)]
enum Foo<T: MyTraitWhichIsCopy> {
A,
B(T),
}
trait MyTraitWhichIsCopy: Copy {}
Upvotes: 1