2014-09-06 3 views
9

मैं एक समस्या यह है कि में सरल में भाग निम्नलिखित:क्या मैं एक इटरेटर लिख सकता हूं जो खुद को बदलता है और फिर खुद में एक संदर्भ उत्पन्न करता है?

struct MyIter { 
    vec: Vec<i8>, 
} 

fn fill_with_useful_data(v: &mut Vec<i8>) { 
    /* ... */ 
} 

impl<'a> Iterator for MyIter { 
    type Item = &'a [i8]; 

    fn next(&mut self) -> Option<&'a [i8]> { 
     fill_with_useful_data(&mut self.vec); 

     Some(&self.vec) 
    } 
} 

fn main() { 
    for slice in (MyIter { vec: Vec::new() }) { 
     println!("{}", slice); 
    } 
} 

यह त्रुटि उत्पन्न करता है:

error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates 
--> src/main.rs:9:6 
    | 
9 | impl<'a> Iterator for MyIter { 
    |  ^^ unconstrained lifetime parameter 

विचार है कि इटरेटर काम का एक समूह है कि अपने क्षेत्र में और कम से दर्शाता करता है प्रत्येक चरण, यह कॉलिंग कोड में खुद को संदर्भ देता है। इस मामले में मैं इसे संदर्भ के बजाय राज्य की एक प्रति प्राप्त करने के रूप में मॉडल कर सकता हूं, लेकिन आइए दिखाएं कि यह संभव नहीं है या केवल असुविधाजनक महंगा है।

Intuitively यह एक समस्या है क्योंकि उधार चेकर सुनिश्चित कर सकते हैं कि .next() फिर से, जबकि सामने आए संदर्भ अभी भी इटरेटर के राज्य निरीक्षण करने के लिए इस्तेमाल किया जा सकता नहीं बुलाया जाता है नहीं होना चाहिए, लेकिन Iterator विशेषता के लिए प्रदान करने के लिए प्रतीत नहीं होता उस तरह की चीज सीधे। यहां तक ​​कि कुछ क्रमिकताओं के साथ ही इटेटरेटर में वेक्टर के संदर्भ में या केवल इटेटरेटर को संदर्भ में या कुछ प्रकार के जीवन में प्राप्त करने के लिए कुछ बनाने के लिए, मुझे उधार चेकर के पीछे कुछ भी नहीं मिल सकता है।

मैंने ब्लॉग पोस्ट पर "Iterators yielding mutable references" पढ़ा लेकिन मुझे यकीन नहीं है कि यह मेरी समस्या पर लागू होता है या नहीं, जिसमें परिवर्तनीय संदर्भ शामिल नहीं हैं।

उत्तर

10

यह संभव नहीं है। अगर इसे अनुमति दी गई तो next फिर से कॉल कर सकता है और इस प्रकार डेटा को संशोधित कर सकता है जो & के माध्यम से भी दिखाई देता है या यहां तक ​​कि संदर्भ को पूरी तरह से अमान्य कर देता है। ऐसा इसलिए है क्योंकि self ऑब्जेक्ट के बीच कोई कनेक्शन नहीं है और लौटा संदर्भ: उन्हें जोड़ने से कोई स्पष्ट जीवनकाल नहीं है।

संकलक इस बारे में कारण और self में एक संदर्भ अगले तरह

fn next(&'a mut self) -> Option<&'a [i8]> 

हालांकि एक हस्ताक्षर की जरूरत लौटने की अनुमति देते हैं, इस विशेषता के हस्ताक्षर जो सामान्य कोड है कि बस के रूप में लेता है की अनुमति नहीं है से अलग है करने के लिए T: Iterator<...> यह नहीं बता सकता कि T के लिए वापसी मूल्य के उपयोग पर अलग-अलग आवश्यकताएं हैं; सभी को समान रूप से संभालना होगा।

Iterator विशेषता रीट वैल्यू के लिए डिज़ाइन की गई है जो इटरेटर ऑब्जेक्ट से स्वतंत्र हैं, जो .collect जैसे इयरेटर एडाप्टर के लिए जरूरी है और सही और सुरक्षित हो। यह कई उपयोगों के लिए आवश्यक से अधिक प्रतिबंधित है (उदाहरण के लिए for लूप के अंदर एक क्षणिक उपयोग) लेकिन यह इस समय है। मुझे नहीं लगता कि हमारे पास इस विशेषता/लूप के लिए सही तरीके से सामान्यीकरण के लिए उपकरण हैं (विशेष रूप से, मुझे लगता है कि हमें उच्च रैंक जीवनकाल वाले जुड़े प्रकारों की आवश्यकता है), लेकिन शायद भविष्य में।

+0

ठीक है, मैंने अभी 'इटरेटर' को लागू करना बंद कर दिया है और मैक्रो के साथ अपना स्वयं का लूप बनाया है। मैंने नहीं सोचा था कि कैसे .collect() 'काम नहीं करेगा। – ben

+0

यह ट्रैवर्सल के लिए भी अच्छा है जहां आप 'for' loop का उपयोग नहीं कर सकते: 'जबकि कुछ (तत्व) = iter.next() {...' – bluss

+1

भविष्य के संदर्भ के लिए, इस प्रकार के इटरेटर ('fn अगला (और 'स्वयं) ') को अक्सर * स्ट्रीमिंग इटरेटर * के रूप में जाना जाता है। चर्चाओं के कुछ नमूने [1] (https://users.rust-lang.org/t/returning-borrowed-values-from-an-iterator/1096), [2] (https://www.reddit.com/आर/जंग/टिप्पणियां/2t1rxx/more_general_iterator_trait /), और एक [क्रेट जो इसके रूप को लागू करता है] (https://github.com/sfackler/streaming-iterator)। – Shepmaster

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