How do I implement Copy and Clone for a type that contains a String (or any type that doesn't implement Copy)?
I have an enum in Rust which has one value that takes a String
:
#[derive(Clone, Copy)]
enum Simple {
Error(String),
Okay,
Foo([u32; 5]),
}
fn main() {
let x = Simple::Error(String::from("blah"));
let y = x.clone();
}
The enum value Foo
above represents about 10 other enums I use that take copyable types or arrays of them. The compiler doesn't seem to complain about them, only the Error(String)
which causes this:
error[E0204]: the trait `Copy` may not be implemented for this type
--> src/main.rs:1:17
|
1 | #[derive(Clone, Copy)]
| ^^^^
2 | enum Simple {
3 | Error(String),
| ------ this field does not implement `Copy`
|
For some reason, String
is not copyable. I don't get this. How do I implement Clone
for an enum for just the one type which has a problem while using the default impl for the rest?
Solution 1:
Copy
Copy
designates types for which making a bitwise copy creates a valid instance without invalidating the original instance.
This isn't true for String
, because String
contains a pointer to the string data on the heap and assumes it has unique ownership of that data. When you drop a String
, it deallocates the data on the heap. If you had made a bitwise copy of a String
, then both instances would try to deallocate the same memory block, which is undefined behaviour.
Since String
doesn't implement Copy
, your enum
cannot implement Copy
either because the compiler enforces that Copy
types are composed only of Copy
data members.
Clone
Clone
merely provides a standard clone
method, and it's up to each implementor to decide how to implement it. String
does implement Clone
, so you can put #[derive(Clone)]
on your enum
.
Solution 2:
I did some exploring to see what a manual implementation would look like for an enum. I came up with this, but keep in mind you can also do #[derive(Clone)]
as stated elsewhere and the compiler will do this for you.
enum Simple {
Error(String),
Okay,
Foo([u32; 5]),
}
impl Clone for Simple {
fn clone(&self) -> Simple {
match self {
Error(a) => Error(a.to_string()),
Okay => Okay,
Foo(a) => Foo(a.clone()),
}
}
}