2016-04-07 20 views
6

चलो कहते हैं कि मैं कुछ विशेषता करते हैं के लिए उधार: को लागू करने के लिए एक प्रकार लागू करता है कि विशेषता

trait MyTrait { 
    fn function1(&self); 
} 

और कुछ प्रकार है कि यह लागू करता है:

struct MyStruct { 
    number: i32, 
} 
impl MyTrait for MyStruct { 
    fn function1(&self) { 
     printn!("{}", self.number); 
    } 
} 
अब मैं एक और प्रकार, ले जाना चाहता है जो है

चीजें जो MyTrait लागू करती हैं। यह परवाह नहीं करता कि वे स्वामित्व में हैं या नहीं। चारों ओर पढ़ने से, यह पूरा करने के सही तरीके की तरह लगता है कि X या &X या 0 जो भी हो, उसे Borrow<X> लेना है। यह बात प्रकार X, या Rc<X> या Box<X>, आदि की बातें ले सकते हैं ...

मैं इस काम के X एक ठोस प्रकार है जब मिल गया है, लेकिन मैं इसे कैसे काम करते हैं जब X एक विशेषता है कर सकता हूँ? ,

struct Consumer<T> { 
    inner: T 
} 

impl<T: Borrow<MyTrait>> Consumer<T> { 
    pub fn new(inner: T) -> Consumer<T> { 
     Consumer { 
      inner: inner 
     } 
    } 
    pub fn do_stuff(&self) { 
     self.inner.borrow().function1(); 
    } 
} 

fn main() { 
    // I want to eventually be able to swap this out for x = Rc::new(MyStruct ... 
    // but I'll keep it simple for now. 
    let x = MyStruct { number: 42 }; 
    let c = Consumer::new(x); 
    c.do_stuff(); 
} 

यह अभी तक काम नहीं करता क्योंकि MyStruct लागू करता Borrow<MyStruct>, लेकिन नहीं Borrow<MyTrait>:

यहाँ क्या मैं पहली बार कोशिश की है। ठीक है, तो उस को लागू करने की कोशिश करते हैं:

<anon>:33:5: 35:6 error: method `borrow` has an incompatible type for trait: 
expected bound lifetime parameter , 
    found concrete lifetime [E0053] 
<anon>:33  fn borrow(&self) -> &MyTrait { 
<anon>:34   self 
<anon>:35  } 
<anon>:33:5: 35:6 help: see the detailed explanation for E0053 
error: aborting due to previous error 
playpen: application terminated with error code 101 

क्या:

impl Borrow<MyTrait> for MyStruct { 
    fn borrow(&self) -> &MyTrait { 
     self 
    } 
} 

यह मैं निम्न त्रुटि है, जो मुझे समझ नहीं आता देता है? वहां पर किसी भी ठोस जीवनकाल का उल्लेख नहीं किया गया है, और Borrow किसी भी जीवनकाल के बिना परिभाषित किया गया है। मैं उलझन में हूं।

सबसे पहले, क्या मेरी धारणाएं सही हैं कि Borrow का उपयोग करने का सही तरीका है? और यदि हां, तो मैं एक विशेषता के Borrow को कैसे कार्यान्वित करूं?

उत्तर

6

कार्यान्वयन लिखने के लिए सही तरीका यह है:

impl<'a> Borrow<MyTrait + 'a> for MyStruct { 
    fn borrow(&self) -> &(MyTrait + 'a) { 
     self 
    } 
} 

विशेषता वस्तुओं एक जीवन भर के लिए बाध्य के साथ प्रतिबंधित किया जा सकता। ऐसा इसलिए है क्योंकि एक प्रकार जो एक विशेषता लागू करता है, में संदर्भ हो सकते हैं, और कुछ परिस्थितियों में, हमें उस वस्तु को अलग करने में सक्षम होना चाहिए जो किसी ऑब्जेक्ट से उधारित वस्तुओं पर निर्भर करता है। यदि आजीवन बाध्य निर्दिष्ट नहीं है, तो मुझे लगता है कि यह 'static पर डिफ़ॉल्ट है; हालांकि, वापसी प्रकार compiles (यह, कम सामान्य है ताकि आप सामान्य समाधान ऊपर एहसान चाहिए), इसलिए इस मुद्दे को आप का सामना करना पड़ा है कि अधिक से अधिक सूक्ष्म है ...

+0

आह, धन्यवाद! मैंने पहले कभी नहीं देखा था (और MyTrait + 'ए)' वाक्यविन्यास पहले। मैंने देखा है कि जेनेरिक पैरामीटर में अन्य प्रकारों में, या टाइप सीमाओं में, लेकिन पहले कभी नहीं। –

3

एक के रूप में एक तरफ के रूप में &(MyTrait + 'static) निर्दिष्ट करते समय, मैं एक वैकल्पिक रास्ता मिल गया ऐसा करने के लिए, कि सभी Borrow<MyTrait> को लागू करने की आवश्यकता नहीं है: इसके बजाय impl<T: Borrow<MyTrait> Consumer<T> होने के

, हम Consumer एक अतिरिक्त पैरामीटर है कि निर्दिष्ट करता है जिनकी क्या वास्तविक उधार प्रकार हो जाएगा ले कर सकते हैं, और फिर उस प्रकार विवश विशेषता लागू करने के लिए । इस तरह:

impl<T: Borrow<Borrowed>, Borrowed: MyTrait> Consumer<T, Borrowed> { 

यह Consumer की आवश्यकता है एक PhantomData सदस्य का संदर्भ देता है अन्यथा अप्रयुक्त Borrowed प्रकार पैरामीटर है।यहाँ एक पूर्ण कार्यान्वयन है:

struct Consumer<T, Borrowed> { 
    inner: T, 
    phantom: PhantomData<Borrowed> 
} 

impl<T: Borrow<Borrowed>, Borrowed: MyTrait> Consumer<T, Borrowed> { 
    fn new(inner: T) -> Consumer<T, Borrowed> { 
     Consumer { 
      inner: inner, 
      phantom: PhantomData 
     } 
    } 
    pub fn do_stuff(&self) { // this function is the same as before. 
     self.inner.borrow().function1(); 
    } 
} 

यह विकल्प, अच्छा गुण है कि यह उन्हें अंदर सामान्य तरीकों के साथ लक्षण का उपयोग कर की अनुमति देता है, क्योंकि यह किसी भी बनाने विशेषता वस्तुओं (विशेषता वस्तुओं लक्षण के लिए नहीं किया जा सकता की आवश्यकता नहीं है कि सामान्य कार्य करें: https://doc.rust-lang.org/error-index.html#method-has-generic-type-parameters देखें)।

एक नकारात्मक पक्ष यह है कि Consumer अब अपने सामान्य पैरामीटर के रूप में संकेत दिए जाने चाहिए। आपको इसे शामिल ठोस प्रकार को बताना होगा:

fn main() { 
    let x = MyStruct { number: 42 }; 
    let c = Consumer::<_, MyStruct>::new(x); 
    c.do_stuff(); 
} 
+2

'उधार' प्रकार पैरामीटर आवश्यक है क्योंकि एक प्रकार 'उधार ' के कई उदाहरण लागू कर सकता है। यदि 'उधार' के प्रकार प्रकार के पैरामीटर के बजाय एक संबद्ध प्रकार था, तो आपके 'impl' पर अतिरिक्त प्रकार पैरामीटर आवश्यक नहीं होगा; आप 'टी :: लक्ष्य: MyTrait' जैसी बाध्य जोड़ने के लिए 'कहां' खंड का उपयोग कर सकते हैं। 'डेफ्र' का एक संबद्ध प्रकार है, लेकिन इसे 'लक्ष्य = टी' के साथ 'टी' के लिए लागू नहीं किया गया है। आप शायद अपनी खुद की विशेषता को परिभाषित कर सकते हैं, लेकिन जब तक कि विशेषज्ञता या नकारात्मक विशेषता सीमा लागू नहीं की जाती है, तब तक आप कार्यान्वयन प्रदान करने के लिए मौजूदा विशेषता का लाभ नहीं उठा सकते। –

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