Ho scritto un programma che ha trait Animal
e struct Dog
che implementa il tratto e struct AnimalHouse
memorizzando un animale come oggetto tratto Box<Animal>
.Come clonare una struttura che memorizza un oggetto tratto?
trait Animal{
fn speak(&self);
}
struct Dog{
name: String
}
impl Dog{
fn new(name: &str) -> Dog {
return Dog{name: name.to_string()}
}
}
impl Animal for Dog{
fn speak(&self){
println!{"{}: ruff, ruff!", self.name};
}
}
struct AnimalHouse{
animal: Box<Animal>
}
fn main(){
let house = AnimalHouse{animal: Box::new(Dog::new("Bobby"))};
house.animal.speak();
}
Funziona perfettamente e restituisce "Bobby: ruff, ruff!" come previsto.
Ma se provo a clonare house
il compilatore restituisce errori
fn main(){
let house = AnimalHouse{animal: Box::new(Dog::new("Bobby"))};
let house2 = house.clone()
house2.animal.speak();
}
32:31 error: type `AnimalHouse` does not implement any method in scope named `clone` let house2 = house.clone(); ^~~~~~~ 32:31 help: methods from traits can only be called if the trait is implemented and in scope; the following trait defines a method `clone`, perhaps you need to implement it: 32:31 help: candidate #1: `core::clone::Clone` error: aborting due to previous error
Ho provato ad aggiungere #[derive(Clone)]
prima struct AnimalHouse
e ha ottenuto un altro errore:
24:24 error: the trait `core::marker::Sized` is not implemented for the type `Animal` [E0277] animal: Box ^~~~~~~~~~~~~~~~~~~ 22:15 note: in expansion of #[derive_Clone] 22:15 note: expansion site 24:24 note: `Animal` does not have a constant size known at compile-time animal: Box ^~~~~~~~~~~~~~~~~~~ 22:15 note: in expansion of #[derive_Clone] 22:15 note: expansion site 24:24 error: the trait `core::clone::Clone` is not implemented for the type `Animal` [E0277] animal: Box ^~~~~~~~~~~~~~~~~~~ 22:15 note: in expansion of #[derive_Clone] 22:15 note: expansion site error: aborting due to 2 previous errors
Quindi, come fare lo struct Animal House
clonabile? È normale che la ruggine usi attivamente un oggetto tratto (in generale)?
Mettere 'clone_box' come un metodo sul tratto stesso è piuttosto inefficiente, richiedendo a tutti gli implementatori di implementarlo nello stesso modo. Una soluzione migliore è quella di avere una supertrait di 'Animal' con un'implementazione coperta per' T: Animal + Clone'. * Questo * è l'approccio utilizzato in cose come AnyMap. –
@ChrisMorgan: buona idea; cambiato. –