How to clone a structure that stores an object as a hatch?

I wrote a program with the tag Animal and struct Dog that implements this trait. It also has an AnimalHouse structure that stores the animal as a Box<Animal> object.

 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(); } 

He returns "Bobby: ruff, ruff!" as expected, but if I try to clone house , the compiler returns errors:

 fn main() { let house = AnimalHouse { animal: Box::new(Dog::new("Bobby")), }; let house2 = house.clone(); house2.animal.speak(); } 
 error[E0599]: no method named `clone` found for type `AnimalHouse` in the current scope --> src/main.rs:31:24 | 23 | struct AnimalHouse { | ------------------ method `clone` not found for this ... 31 | let house2 = house.clone(); | ^^^^^ | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: candidate #1: `std::clone::Clone` 

I tried adding #[derive(Clone)] to struct AnimalHouse and got another error:

 error[E0277]: the trait bound `Animal: std::clone::Clone` is not satisfied --> src/main.rs:25:5 | 25 | animal: Box<Animal>, | ^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `Animal` | = note: required because of the requirements on the impl of `std::clone::Clone` for `std::boxed::Box<Animal>` = note: required by `std::clone::Clone::clone` 

How to make struct AnimalHouse cloneable? Is idiomatic rust actively using an object-sign? At all?

+5
source share
2 answers

There are several issues. First, there is no need to require Animal also implement Clone . You can fix this by changing the definition of the characteristic:

 trait Animal: Clone { /* ... */ } 

This will cause Animal cease to be safe with respect to the object, which means that the Box<Animal> will become invalid, so it’s not big.

What you can do is insert an extra step. To whit (with additions from @ChrisMorgan comment ).

 trait Animal: AnimalClone { fn speak(&self); } // Splitting AnimalClone into its own trait allows us to provide a blanket // implementation for all compatible types, without having to implement the // rest of Animal. In this case, we implement it for all types that have // 'static lifetime (*ie* they don't contain non-'static pointers), and // implement both Animal and Clone. Don't ask me how the compiler resolves // implementing AnimalClone for Animal when Animal requires AnimalClone; I // have *no* idea why this works. trait AnimalClone { fn clone_box(&self) -> Box<Animal>; } impl<T> AnimalClone for T where T: 'static + Animal + Clone, { fn clone_box(&self) -> Box<Animal> { Box::new(self.clone()) } } // We can now implement Clone manually by forwarding to clone_box. impl Clone for Box<Animal> { fn clone(&self) -> Box<Animal> { self.clone_box() } } #[derive(Clone)] struct Dog { name: String, } impl Dog { fn new(name: &str) -> Dog { Dog { name: name.to_string(), } } } impl Animal for Dog { fn speak(&self) { println!("{}: ruff, ruff!", self.name); } } #[derive(Clone)] struct AnimalHouse { animal: Box<Animal>, } fn main() { let house = AnimalHouse { animal: Box::new(Dog::new("Bobby")), }; let house2 = house.clone(); house2.animal.speak(); } 

By introducing clone_box , we can get around the problem of trying to clone an attribute object.

+10
source

The previous answer correctly answers the question about saving an object with boxes.

Distracting the topic from the name, but not about the idiomatic way of using feature objects, an alternative solution could be to use the Rc smart pointer instead of Box : this avoids a workaround to bypass the security object:

 #[derive(Clone)] struct AnimalHouse { animal: Rc<Animal>, } fn main() { let house = AnimalHouse { animal: Rc::new(Dog::new("Bobby")) }; let house2 = house.clone(); house2.animal.speak(); } 

Note : Rc<T> used only for single-threaded scripts; there is also Arc<T> .

+2
source

All Articles