2016-10-03 9 views
11

मैं उधार चेकर के साथ लड़ रहा हूं। मेरे पास कोड के दो समान टुकड़े हैं, एक काम कर रहा है जैसा कि मैं उम्मीद करता हूं, और दूसरा नहीं।किसने एक चर उधार लिया?

एक है कि काम करता है मैं उम्मीद के रूप में:

mod case1 { 
    struct Foo {} 

    struct Bar1 { 
     x: Foo, 
    } 

    impl Bar1 { 
     fn f<'a>(&'a mut self) -> &'a Foo { 
      &self.x 
     } 
    } 

    // only for example 
    fn f1() { 
     let mut bar = Bar1 { x: Foo {} }; 
     let y = bar.f(); // (1) 'bar' is borrowed by 'y' 
     let z = bar.f(); // error (as expected) : cannot borrow `bar` as mutable more 
          // than once at a time [E0499] 
    } 

    fn f2() { 
     let mut bar = Bar1 { x: Foo {} }; 
     bar.f(); // (2) 'bar' is not borrowed after the call 
     let z = bar.f(); // ok (as expected) 
    } 
} 

एक है कि नहीं करता है:

mod case2 { 
    struct Foo {} 

    struct Bar2<'b> { 
     x: &'b Foo, 
    } 

    impl<'b> Bar2<'b> { 
     fn f(&'b mut self) -> &'b Foo { 
      self.x 
     } 
    } 

    fn f4() { 
     let foo = Foo {}; 
     let mut bar2 = Bar2 { x: &foo }; 
     bar2.f(); // (3) 'bar2' is borrowed as mutable, but who borrowed it? 
     let z = bar2.f(); // error: cannot borrow `bar2` as mutable more than once at a time [E0499] 
    } 
} 

मैं आशा व्यक्त की मैं संकलक परेशान बिना दो बार Bar2::f कह सकते हैं मामले में 1 के रूप में,।

प्रश्न टिप्पणी में है (3): bar2 उधार लिया, जबकि कोई प्रभाव नहीं है?

यहाँ मैं क्या समझ है:

  1. मामले 1 में, f2 कॉल: जीवन पैरामीटर 'a प्राप्त &Foo मूल्य में से एक है, इसलिए इस जीवन में खाली है जब वहाँ कोई दिखावा है, और bar है Bar1::f कॉल के बाद उधार नहीं लिया गया;

  2. मामले 2 में, bar2 उधार लेता है foo (अपरिवर्तनीय के रूप में) है, तो जीवन भर पैरामीटर 'bBar2 struct में foo संदर्भ जीवन है, जो f4 शरीर के अंत में समाप्त होता है। उस जीवनकाल के लिए Bar2::f बोरो bar2 पर कॉल करना, अर्थात् f4 के अंत तक।

लेकिन सवाल अभी भी है: bar2 किसने उधार लिया? क्या यह Bar2::f हो सकता है? कॉल के बाद उधार लिया स्वामित्व कैसे Bar2::f होगा? मुझे यहां क्या समझ नहीं आ रहा है?

मैं x86_64-pc-windows-msvc पर जंग 1.14.0-रात (86affcdf6 2016-09-28) का उपयोग कर रहा हूं।

उत्तर

7

आह ... आप मूल रूप से स्वयं को उधार लेते हैं।

यह मुद्दा इस तथ्य पर निर्भर करता है कि आपके पास जीवन भर ('b) Foo और Bar के जीवनकाल दोनों के लिए उपयोग किया जाता है। संकलक तब उन जीवनकाल को कर्तव्यपूर्वक एकजुट करता है, और आप एक अजीब परिस्थिति में समाप्त होते हैं जहां अचानक उधार के जीवनकाल को बयान के अंत में समाप्त होना चाहिए, इसके बाद मूल्य समाप्त होने के बाद समाप्त हो जाना चाहिए।

अंगूठे के नियम के रूप में: हमेशाself के लिए एक नया जीवनकाल का उपयोग करें। कुछ और अजीब है।


यह ध्यान रखें कि इस पद्धति वास्तव में (अपरिवर्तनीय उधार के साथ हालांकि अधिक होने की संभावना) उपयोगी हो सकता है दिलचस्प है: यह ढेर फ्रेम करने के लिए एक मूल्य के प्रस्तोता, कार्य करने के लिए कॉल के बाद किसी भी कदम को रोकने के लिए अनुमति देता है, जो कि (कभी-कभी) उधार का प्रतिनिधित्व करने के लिए उपयोगी होता है जो जंग द्वारा अच्छी तरह से तैयार नहीं होता है (जैसे एफएफआई के मूल्य पर सूचक को पास करना)।

+0

अंगूठे के इस मूल्यवान नियम के कारण स्वीकृत। धन्यवाद। – jferard

1

मैं एक main() में f4() के शरीर रखा है और पता लगाने के लिए Bar2 के लिए Drop लागू किया जब यह गिरा दिया जाता है (यानी दायरे से बाहर चला जाता है):

impl<'b> Drop for Bar2<'b> { 
    fn drop(&mut self) { println!("dropping Bar2!"); } 
} 

और परिणाम था:

error: `bar2` does not live long enough 
    --> <anon>:24:5 
    | 
24 |  bar2.f(); 
    |  ^^^^ does not live long enough 
25 | } 
    | - borrowed value dropped before borrower 
    | 
    = note: values in a scope are dropped in the opposite order they are created 

कुछ ख़राब है; के, विस्तार से जांच सहायक स्कोप के साथ करते हैं:

fn main() { 
    { 
     let foo = Foo {}; // foo scope begins 
     { 
      let mut bar2 = Bar2 { x: &foo }; // bar2 scope begins; bar2 borrows foo 
      bar2.f(); 
     } // bar2 should be dropped here, but it has the same lifetime as foo, which is still live 
    } // foo is dropped (its scope ends) 
} 

यह मेरे लिए लग रहा है एक रिसाव यहाँ है वहाँ कि और bar2 गिरा दिया कभी नहीं है (और इस प्रकार Drop लागू नहीं किया जा सकता है इसके लिए)। यही कारण है कि आप इसे फिर से उधार नहीं ले सकते हैं।

8

# 2 मामले में, आप इस राशि:

impl<'b> Bar2<'b> { 
    fn f(&'b mut self) -> &'b Foo { 
     self.x 
    } 
} 

हाइलाइट करने के लिए: &'b mut self और &'b Foo ही जीवन निर्दिष्ट किया है।

यह कह रहा है कि self का संदर्भ और Foo के उदाहरण के लिए लौटा संदर्भ दोनों एक ही जीवनकाल है। कॉल साइट को देखते हुए, आप इस राशि:

let foo = Foo {}; 
let mut bar2 = Bar2 { x: &foo }; 

तो संकलक का निष्कर्ष निकालते है कि foo और bar2 दोनों एक ही जीवन है। foo का जीवनकाल f4 फ़ंक्शन का दायरा है, और इसलिए bar2 पर उत्परिवर्तनीय संदर्भ यह साझा करता है।

एक तरीका यह तय करने के लिए, self संदर्भ पर स्पष्ट जीवन भर दूर करने के लिए है:

fn f(&mut self) -> &'b Foo 

यह संकलित करता है तथा संकलक सही तरीके से समझता है कि bar2 के संदर्भ में और foo के संदर्भ में विभिन्न जीवन काल की है।

खेल का मैदान: https://play.rust-lang.org/?gist=caf262dd628cf14cc2884a3af842276a&version=stable&backtrace=0

TLDR: हाँ, आत्म संदर्भ और लौट आए संदर्भ पर एक ही जीवन विनिर्देशक होने का मतलब है कि f4 के संपूर्ण दायरे bar2 की एक परिवर्तनशील उधार आयोजित करता है।

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