J'ai un enum dans Rust qui a une valeur qui prend une String
. Ceci peut être démontré avec cet exemple simple:
#[derive(Clone, Copy)]
enum Simple {
Error(String),
Okay,
Foo([u32; 5]),
}
fn main() {
let x = Simple::Error(String::from("blah"));
let y = x.clone();
}
La valeur enum Foo
ci-dessus représente environ 10 autres enums que j'utilise et qui prennent des types ou des tableaux pouvant être copiés. Le compilateur ne semble pas s'en plaindre, seulement la Error(String)
qui provoque ceci:
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`
Pour une raison quelconque, String
n'est pas copiable. Je ne comprends pas ça. Comment implémenter Clone
pour une énumération pour le seul type qui rencontre un problème lors de l'utilisation de l'impl par défaut pour le reste?
Copy
désigne les types pour lesquels faire une copie au niveau du bit crée une instance valide sans invalider l'instance d'origine.
Ce n'est pas vrai pour String
, parce que String
contient un pointeur sur les données de chaîne sur le segment de mémoire et suppose qu'il est le propriétaire unique de ces données. Lorsque vous supprimez une String
, les données du tas sont libérées. Si vous aviez fait une copie au niveau du bit d'une String
, les deux instances essaieraient de désallouer le même bloc de mémoire, ce qui est comportement non défini.
Puisque String
n'implémente pas Copy
, votre enum
ne peut pas implémenter Copy
non plus car le compilateur impose que les types Copy
soient composés uniquement de données membres Copy
.
Clone
fournit simplement une méthode clone
standard, et il appartient à chaque implémenteur de décider de la façon dont elle doit être mise en œuvre. String
implémente Clone
, de sorte que vous pouvez mettez #[derive(Clone)]
sur votre enum
.
J'ai fait quelques recherches pour voir à quoi ressemblerait une implémentation manuelle. Je suis venu avec cela, mais gardez à l'esprit que vous pouvez aussi faire #[derive(Clone)]
comme indiqué ailleurs et le compilateur le fera pour vous.
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()),
}
}
}