2016-08-02 4 views
9

मुझे समझ में नहीं आ रहा है कि उधारकर्ता उधारकर्ता चर का उधारकर्ता अंतराल के दायरे के बाद क्यों उधार लिया जाता है। ऐसा लगता है कि यह उपयोग लक्षण से संबंधित है, लेकिन मैं क्यों नहीं दिख रहा है:उधारकर्ता का दायरा समाप्त होने पर चर उधार नहीं ले सकता

fn main() { 
    let mut a = 10; 
    test::<FooS>(&mut a); 
    println!("out {:?}", a) 
} 

trait Foo<'a> { 
    fn new(data: &'a mut u32) -> Self; 
    fn apply(&mut self); 
} 

struct FooS<'a> { 
    data: &'a mut u32, 
} 

impl<'a> Foo<'a> for FooS<'a> { 
    fn new(data: &'a mut u32) -> Self { 
     FooS { data: data } 
    } 

    fn apply(&mut self) { 
     *self.data += 10; 
    } 
} 

fn test<'a, F>(data: &'a mut u32) 
    where F: Foo<'a> 
{ 
    { 
     // let mut foo = FooS {data: data}; // This works fine 
     let mut foo: F = Foo::new(data); 
     foo.apply(); 
    } // foo scope ends here 
    println!("{:?}", data); // error 
} // but borrowed till here 

try online

error: cannot borrow `data` as immutable because `*data` is also borrowed as mutable [--explain E0502] 
    --> <anon>:34:22 
31 |>   let mut foo: F = Foo::new(data); 
    |>         ---- mutable borrow occurs here 
... 
34 |>  println!("{:?}", data); // error 
    |>      ^^^^ immutable borrow occurs here 
35 |> } // but borrowed till here 
    |> - mutable borrow ends here 
+1

https://play.rust-lang.org/?gist=dabe17d66a14e72c2ca67e064ca26601&version=nightly&backtrace=0 काम करता है। तो ... – Jacob

+0

फिर भी, यह एक बग प्रतीत होता है। विस्तृत उत्तर के लिए – JDemler

उत्तर

8

test समारोह है कि प्रकार F लागू करता Foo<'a> की आवश्यकता है। 'a एक जीवनकाल पैरामीटर है जो फ़ंक्शन को पास कर दिया गया है। लाइफटाइम पैरामीटर हमेशा जीवनकाल का प्रतिनिधित्व करते हैं जो फ़ंक्शन कॉल से अधिक समय तक जीवित रहते हैं - क्योंकि कोई भी कॉलर कम जीवनकाल के साथ संदर्भ प्रदान नहीं कर सकता है; आप स्थानीय चर के संदर्भ को से दूसरे फ़ंक्शन से कैसे पारित कर सकते हैं? -, और उधार जांच (जो एक समारोह के लिए स्थानीय है) के प्रयोजनों के लिए, संकलक मानता है कि उधार पूरे समारोह कॉल को कवर करता है।

इसलिए, जब आप Foo::new करने के लिए कॉल से F का एक उदाहरण बनाने के लिए, आप एक वस्तु है कि जीवन भर 'a के साथ कुछ उधार लेता है, एक जीवन भर है कि पूरे समारोह कॉल को शामिल किया गया पैदा करते हैं।

यह समझना महत्वपूर्ण है कि जब आप test::<FooS> फोन, संकलक वास्तव में FooS<'a> के लिए एक जीवन भर के पैरामीटर में भर जाता है के लिए महत्वपूर्ण है, तो आप test::<FooS<'a>>, जहां 'a (क्षेत्र है कि बयान है कि समारोह कॉल शामिल शामिल किया गया है, क्योंकि &mut a है बुला अंत एक अस्थायी अभिव्यक्ति)। इसलिए, संकलक सोचता है कि FooS जो test में बनाया जाएगा, test पर कॉल के साथ कथन के अंत तक कुछ उधार लेगा! nongeneric संस्करण के साथ

आइए इसके विपरीत इस:

let mut foo = FooS {data: data}; 

इस संस्करण में, संकलक test में FooS<'a> के लिए एक ठोस जीवन चुनता है, बल्कि main की तुलना में, तो यह ब्लॉक प्रत्यय छोर से विस्तार का चयन करेंगे ब्लॉक के अंत में let कथन का, जिसका अर्थ है कि data का अगला उधार ओवरलैप नहीं होता है और कोई संघर्ष नहीं होता है।

क्या आप वास्तव में चाहते हैं कि F कुछ जीवन 'x कि 'a तुलना में कम है के लिए लागू Foo<'x>, और सबसे महत्वपूर्ण यह है कि जीवन भर के समारोह में मौजूद क्षेत्र में होना चाहिए, न कि एक enclosing एक 'a की तरह है।

इस समस्या का जंग का वर्तमान समाधान उच्च रैंकिंग विशेषता सीमा है। यह इस तरह दिखता है:

fn test<'a, F>(data: &'a mut u32) 
    where F: for<'x> Foo<'x> 
{ 
    { 
     let mut foo: F = Foo::new(data); 
     foo.apply(); 
    } 
    println!("{:?}", data); 
} 

शब्दों में, इसका मतलब है प्रकार F हर संभव 'x के लिए Foo<'x> को लागू करना चाहिए।

test के इस संस्करण में अपने दम पर संकलित करते हैं, हम वास्तव में एक प्रकार है कि क्योंकि हर संभव जीवन 'a के लिए इस बाधा को पूरा, आपूर्ति नहीं कर सकते हैं, वहाँ एक अलग प्रकार FooS<'a> कि केवल लागू करता Foo<'a> है।यदि FooS था कोई जीवन भर पैरामीटर और FooS के लिए Foo की impl इस तरह देखा:

impl<'a> Foo<'a> for FooS { 

तो यह ठीक हो जाएगा के बाद से वहाँ एक ही प्रकार FooS कि हर संभव जीवन 'a के लिए Foo<'a> लागू करता है।

बेशक, आप FooS पर जीवनकाल पैरामीटर को नहीं हटा सकते हैं, क्योंकि इसमें उधारकर्ता पॉइंटर होता है। इस समस्या का उचित समाधान एक ऐसी सुविधा है जो जंग के पास अभी तक नहीं है: एक फ़ंक्शन के लिए सामान्य पैरामीटर के रूप में एक प्रकार के कन्स्ट्रक्टर (पूरी तरह से निर्मित प्रकार के बजाय) को पास करने की क्षमता। इस क्षमता के साथ, हम test पर FooS के साथ कॉल कर सकते हैं, एक प्रकार का कन्स्ट्रक्टर जिसे एक ठोस प्रकार का उत्पादन करने के लिए जीवनकाल पैरामीटर की आवश्यकता होती है, कॉल साइट पर ठोस जीवनकाल निर्दिष्ट किए बिना, और कॉलर अपने जीवनकाल की आपूर्ति करने में सक्षम होगा।

+0

धन्यवाद। अभी भी मेरे लिए एक अस्पष्ट क्षण। जैसा कि आपने कहा था "लाइफटाइम पैरामीटर हमेशा जीवनकाल का प्रतिनिधित्व करते हैं जो फ़ंक्शन कॉल से अधिक समय तक रहते हैं, और उधार जांच (जो फ़ंक्शन के लिए स्थानीय है) के प्रयोजनों के लिए, संकलक मानता है कि उधार पूरे फ़ंक्शन कॉल को कवर करता है।" _। क्यों संकलक संकलक इस पर विचार करते हैं? हमारे पास जीवन भर है जो लंबे समय तक रहता है और फिर कार्यक्षेत्र का कार्य करता है। लेकिन उस उधार से संबंधित यह कैसे पूरे समारोह कॉल को शामिल करता है? क्या यह कार्यान्वयन या विनिर्देश का हिस्सा है? –

+0

अभी तक जंग का कोई उचित "विनिर्देशन" नहीं है, इसलिए कार्यान्वयन आपको प्राप्त होने वाली कल्पना के निकटतम चीज़ है। अपने अन्य प्रश्न के लिए, मेरा संपादन देखें। –

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