2015-02-18 5 views
5

उधार मैं एक प्रोग्राम है जो कम या ज्यादा दिखता है इसउधार ली गई सामग्री से बाहर स्थानांतरित नहीं किया जा सकता जब एक सामान्य प्रकार

struct Test<T> { 
    vec: Vec<T> 
} 

impl<T> Test<T> { 
    fn get_first(&self) -> &T { 
     &self.vec[0] 
    } 

    fn do_something_with_x(&self, x: T) { 
     // Irrelevant 
    } 
} 

fn main() { 
    let t = Test { vec: vec![1i32, 2, 3] }; 
    let x = t.get_first(); 
    t.do_something_with_x(*x); 
} 

मूल रूप से की तरह, हम struct Test है कि कुछ मूल्य उधार लेता है पर एक विधि कॉल कर सकते है। फिर हम पहले प्राप्त मूल्य को पार करते हुए, उसी संरचना पर एक और विधि कहते हैं।

यह उदाहरण पूरी तरह से ठीक काम करता है। अब, जब हम main जेनेरिक की सामग्री बनाते हैं, तो यह अब और काम नहीं करता है।

error: cannot move out of borrowed content

src/main.rs:14 let raw_x = *x;

मैं पूरी तरह से यकीन है कि क्यों यह हो रहा है नहीं कर रहा हूँ:

fn generic_main<T>(t: Test<T>) { 
    let x = t.get_first(); 
    t.do_something_with_x(*x); 
} 

तो मैं निम्नलिखित त्रुटि मिलती है। क्या कोई मुझे बता सकता है कि Test<i32>get_first पर कॉल करते समय उधार नहीं लिया जाता है जबकि Test<T> है?

उत्तर

10

संक्षिप्त उत्तर यह है कि i32Copy विशेषता लागू करता है, लेकिन T नहीं है। यदि आप fn generic_main<T: Copy>(t: Test<T>) का उपयोग करते हैं, तो आपकी तत्काल समस्या ठीक हो गई है।

लंबा उत्तर यह है कि Copy एक विशेष विशेषता है जिसका अर्थ है कि बिट्स की प्रतिलिपि बनाकर मूल्यों की प्रतिलिपि बनाई जा सकती है। i32 जैसे Copy लागू करें। String जैसे Copy लागू करें, उदाहरण के लिए, इसे एक ढेर आवंटन की आवश्यकता होती है। यदि आपने बिट्स की प्रतिलिपि बनाकर String की प्रतिलिपि बनाई है, तो आप दो String मानों के साथ समाप्त हो जाएंगे जो स्मृति के समान हिस्से को इंगित करते हैं। यह अच्छा नहीं होगा (यह असुरक्षित है!)।

इसलिए, TCopy बाध्य देना काफी प्रतिबंधित है। एक कम प्रतिबंधक सीमा T: Clone होगी। Clone विशेषता Copy के समान है (इसमें यह मूल्यों की प्रतिलिपि बनाता है), लेकिन आमतौर पर यह "बिट्स की प्रतिलिपि बनाने" से अधिक द्वारा किया जाता है। उदाहरण के लिए, String प्रकार अंतर्निहित स्मृति के लिए एक नया ढेर आवंटन बनाकर Clone लागू करेगा।

यह बदलने के लिए अपने generic_main कैसे लिखा है आप की आवश्यकता है:

fn generic_main<T: Clone>(t: Test<T>) { 
    let x = t.get_first(); 
    t.do_something_with_x(x.clone()); 
} 

वैकल्पिक रूप से, अगर आप या तो Clone या Copy सीमा है नहीं करना चाहते, तो आप अपने do_something_with_x विधि को बदल सकता है एक लेने के लिए T के संदर्भ बल्कि एक स्वामित्व T से:

impl<T> Test<T> { 
    // other methods elided 

    fn do_something_with_x(&self, x: &T) { 
     // Irrelevant 
    } 
} 

और अपने generic_main रहता है ज्यादातर एक ही है, सिवाय इसके कि आप x भिन्नता नहीं है:

fn generic_main<T>(t: Test<T>) { 
    let x = t.get_first(); 
    t.do_something_with_x(x); 
} 

आप Copyin the docs के बारे में अधिक पढ़ सकते हैं। अपने स्वयं के प्रकारों के लिए Copy को कार्यान्वित करने के तरीके सहित कुछ अच्छे उदाहरण हैं।

+0

बहुत उपयोगी उत्तर, बहुत धन्यवाद! – NSAddict

+0

"चलती बिट्स" का उपयोग थोड़ा उलझन में है, क्योंकि जंग चलने से जंग चलती है। शायद "प्रतिलिपि बिट्स" स्पष्ट होगा? –

+0

@MatthieuM। ज़रूर। अपडेट किया गया।इसके लायक होने के लिए, मैंने पिछले शब्द सीधे भाषा संदर्भ से लिया: 'सादा, "सादा पुराने डेटा" प्रकारों के लिए, जिन्हें बस बिट्स चलकर कॉपी किया जा सकता है।' – BurntSushi5

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