2015-05-20 8 views
5

मैंने एक प्रोग्राम लिखा है जिसमें trait Animal और struct Dog विशेषता को लागू करने और struct AnimalHouse एक जानवर को विशेषता वस्तु Box<Animal> के रूप में संग्रहीत करने के लिए लिखा है।एक विशेषता वस्तु भंडारण एक संरचना क्लोन कैसे करें?

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

यह पूरी तरह से काम करता है और "बॉबी: रफ, रफ!" देता है जैसा सोचा था।

लेकिन अगर मैं house क्लोन करने के लिए कोशिश संकलक त्रुटियों

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 

मैं struct AnimalHouse से पहले #[derive(Clone)] जोड़ने की कोशिश की रिटर्न और एक अन्य त्रुटियों मिला:

 
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 

तो कैसे struct बनाने के लिए Animal House क्लोनेबल? क्या जंग के लिए सक्रिय रूप से (आमतौर पर) उपयोग करने के लिए जंग का सामान्य तरीका है?

उत्तर

10

कुछ समस्याएं हैं। पहला यह है कि इसकी आवश्यकता नहीं है कि Animal भी Clone लागू करता है। अब, आप विशेषता परिभाषा बदलकर इसे ठीक कर सकते हैं:

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

लेकिन इस Animal अब सुरक्षित वस्तु, जिसका अर्थ है कि Box<Animal> अवैध हो जाएगा होने के लिए कारण बनता है। तो यह बहुत अच्छा नहीं है।

क्या आप कर सकते हैं एक अतिरिक्त चरण डालें। सफ़ेद करने के लिए:

संपादित करें: @ क्रिसमोर्गन की टिप्पणी के आधार पर निम्नलिखित संशोधित किया गया है।

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 (*i.e.* 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 { 
     return 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(); 
} 

clone_box शुरू करके, हम एक विशेषता वस्तु क्लोन करने के लिए प्रयास कर के साथ समस्याओं के आसपास मिल सकती है।

+0

विशेषता पर एक विधि के रूप में 'clone_box' डालने की बजाय अक्षम है, सभी कार्यान्वयनकर्ताओं को इसे उसी तरह लागू करने की आवश्यकता है। एक बेहतर समाधान यह है कि 'टी: पशु + क्लोन 'के लिए कंबल कार्यान्वयन के साथ' पशु 'की एक सुपरर्ट्रेट के रूप में। * यह * एनीमैप जैसी चीजों में उपयोग किया जाने वाला दृष्टिकोण है। –

+0

@ क्रिस मॉर्गन: अच्छा विचार; बदला हुआ। –

संबंधित मुद्दे