पुनरावृति और it_iter में क्या अंतर है?


175

मैं उदाहरण ट्यूटोरियल द्वारा रस्ट कर रहा हूं जिसमें यह कोड स्निपेट है:

// Vec example
let vec1 = vec![1, 2, 3];
let vec2 = vec![4, 5, 6];

// `iter()` for vecs yields `&i32`. Destructure to `i32`.
println!("2 in vec1: {}", vec1.iter()     .any(|&x| x == 2));
// `into_iter()` for vecs yields `i32`. No destructuring required.
println!("2 in vec2: {}", vec2.into_iter().any(| x| x == 2));

// Array example
let array1 = [1, 2, 3];
let array2 = [4, 5, 6];

// `iter()` for arrays yields `&i32`.
println!("2 in array1: {}", array1.iter()     .any(|&x| x == 2));
// `into_iter()` for arrays unusually yields `&i32`.
println!("2 in array2: {}", array2.into_iter().any(|&x| x == 2));

मैं पूरी तरह से उलझन में हूँ - एक Vecपुनरावृत्ति के लिए iterपैदावार संदर्भों से लौटा है और पुनरावृत्त into_iterपैदावार मूल्यों से लौटा है , लेकिन एक सरणी के लिए ये पुनरावृत्तियां समान हैं?

इन दो तरीकों के लिए उपयोग मामला / एपीआई क्या है?

जवाबों:


147

टी एल; डॉ:

  • संदर्भ के आधार पर, द्वारा लौटाए गए पुनरावृत्त into_iterकिसी भी T, &Tया &mut T, का उत्पादन कर सकते हैं ।
  • इटरेटर द्वारा दिया iterनिकलेगा &Tप्रथा के अनुसार,।
  • इटरेटर द्वारा दिया iter_mutनिकलेगा &mut Tप्रथा के अनुसार,।

पहला सवाल है: "क्या है into_iter?"

into_iterIntoIteratorविशेषता से आता है :

pub trait IntoIterator 
where
    <Self::IntoIter as Iterator>::Item == Self::Item, 
{
    type Item;
    type IntoIter: Iterator;
    fn into_iter(self) -> Self::IntoIter;
}

आप इस विशेषता को तब लागू करते हैं जब आप यह निर्दिष्ट करना चाहते हैं कि किसी विशेष प्रकार को एक पुनरावृत्त में कैसे परिवर्तित किया जाए। सबसे विशेष रूप से, यदि एक प्रकार लागू होता है IntoIteratorतो इसका उपयोग forलूप में किया जा सकता है ।

उदाहरण के लिए, तीन बार Vecलागू IntoIterator...!

impl<T> IntoIterator for Vec<T>
impl<'a, T> IntoIterator for &'a Vec<T>
impl<'a, T> IntoIterator for &'a mut Vec<T>

प्रत्येक संस्करण थोड़ा अलग है।

यह एक की खपत Vecऔर उसके इटरेटर पैदावार मूल्यों ( Tसीधे):

impl<T> IntoIterator for Vec<T> {
    type Item = T;
    type IntoIter = IntoIter<T>;

    fn into_iter(mut self) -> IntoIter<T> { /* ... */ }
}

अन्य दो वेक्टर को संदर्भ द्वारा लेते हैं ( into_iter(self)क्योंकि selfदोनों मामलों में एक संदर्भ नहीं है) के हस्ताक्षर से मूर्ख मत बनो और उनके पुनरावृत्त अंदर के तत्वों के संदर्भ का उत्पादन करेंगे Vec

यह एक पैदावार अपरिवर्तनीय संदर्भ :

impl<'a, T> IntoIterator for &'a Vec<T> {
    type Item = &'a T;
    type IntoIter = slice::Iter<'a, T>;

    fn into_iter(self) -> slice::Iter<'a, T> { /* ... */ }
}

यह एक ओर जहां पैदावार परिवर्तनशील संदर्भ :

impl<'a, T> IntoIterator for &'a mut Vec<T> {
    type Item = &'a mut T;
    type IntoIter = slice::IterMut<'a, T>;

    fn into_iter(self) -> slice::IterMut<'a, T> { /* ... */ }
}

इसलिए:

बीच क्या अंतर है iterऔर into_iter?

into_iterएक पुनरावृत्ति प्राप्त करने के लिए एक सामान्य तरीका है, चाहे यह पुनरावृत्ति मान देता है, अपरिवर्तनीय संदर्भ या परस्पर संदर्भ संदर्भ पर निर्भर है और कभी-कभी आश्चर्यचकित हो सकता है।

iterऔर iter_mutतदर्थ तरीके हैं। उनका रिटर्न प्रकार इसलिए संदर्भ से स्वतंत्र है, और पारंपरिक रूप से पुनरावृत्तियों को अपरिवर्तनीय संदर्भ और उत्परिवर्तनीय संदर्भ प्रदान करेगा।

उदाहरण के आधार पर जंग के लेखक संदर्भ पर निर्भरता से आने वाले आश्चर्य का चित्रण करते हैं (अर्थात, प्रकार) जिस into_iterपर कहा जाता है, और इस तथ्य का उपयोग करके समस्या को भी जटिल कर रहा है:

  1. IntoIteratorके लिए लागू नहीं है [T; N], केवल &[T; N]और के लिए&mut [T; N]
  2. जब किसी विधि को किसी मूल्य के लिए लागू नहीं किया जाता है, तो यह स्वचालित रूप से उस मूल्य के संदर्भ में खोजा जाता है

जो into_iterसभी प्रकारों (अपवादों [T; N]) को लागू करने के बाद से सभी 3 विविधताओं (मूल्य और संदर्भों) के लिए बहुत ही आश्चर्यजनक है । सरणी के लिए इट्रेटर को लागू करना संभव नहीं है जो मानों को पैदावार देता है क्योंकि यह अपने आइटम को छोड़ने के लिए "हटना" नहीं कर सकता है।

के रूप में क्यों arrays लागू करने के लिए IntoIterator(इस तरह के एक आश्चर्य की बात फैशन में): यह forछोरों में उनके संदर्भ में पुनरावृति संभव बनाने के लिए है ।


14
मुझे यह ब्लॉग पोस्ट उपयोगी लगी
poy

> क्या यह पुनरावृत्ति मान देता है, अपरिवर्तनीय संदर्भ या परस्पर संदर्भ संदर्भ निर्भर है इसका क्या अर्थ है और इससे कैसे निपटना है? उदाहरण के लिए, कोई व्यक्ति iter_mut को परस्पर मूल्यों को कैसे बल देगा?
दान एम।

@DanM .: (1) इसका मतलब है कि into_iterरिसीवर के मूल्य, संदर्भ या परस्पर संदर्भ के आधार पर कार्यान्वयन लागू करता है। (२) Rust में कोई भी परिवर्तनशील मूल्य नहीं हैं, या यूँ कहें कि आपके पास कोई भी मूल्य है, जो आपके स्वामित्व का है।
मैथ्यू एम।

@ MatthieuM.hm, मेरे परीक्षणों में ऐसा नहीं लगता है। मैं के लिए IntoIter को क्रियान्वित किया है &'a MyStructऔर &mut 'a MyStructऔर यदि मौजूद है, भले ही मैं कहा जाता है पहले एक हमेशा चुना गया था into_iter().for_each()पर mutसाथ मूल्य &mutलैम्ब्डा में तर्क।
दान एम।

1
@ XXX: धन्यवाद जो बहुत उपयोगी है। मैंने बीच में उत्तर को दफनाने से बचने के लिए सवाल के शीर्ष पर एक टीएल? डीआर प्रदान करने का फैसला किया, आपको क्या लगता है?
मैथ्यू एम।

78

मैं (एक रस्ट नौसिखिया) Google से एक सरल उत्तर की तलाश में आया था जो अन्य उत्तरों द्वारा प्रदान नहीं किया गया था। यहाँ यह आसान जवाब है:

  • iter() संदर्भ द्वारा आइटम पर पुनरावृत्त
  • into_iter() आइटम्स पर पुनरावृत्तियों, उन्हें नए दायरे में ले जाना
  • iter_mut() आइटम्स पर पुनरावृत्तियों, प्रत्येक आइटम के लिए एक परस्पर संदर्भ दे रही है

तो for x in my_vec { ... }अनिवार्य रूप से करने के बराबर है my_vec.into_iter().for_each(|x| ... )दोनों - moveके तत्वों my_vecमें ...गुंजाइश।

यदि आपको केवल डेटा को "देखने" की iterआवश्यकता है, तो उपयोग करें , यदि आपको इसे संपादित / म्यूट करने की आवश्यकता है, तो उपयोग करें iter_mut, और यदि आपको इसे नया मालिक देने की आवश्यकता है, तो उपयोग करें into_iter

यह मददगार था: http://hermanradtke.com/2015/06/22/effectively-use-iterators-in-rust.html

यह एक समुदाय विकी बनाना ताकि उम्मीद है कि अगर मैंने कोई गलती की है तो एक रस्ट प्रो इस उत्तर को संपादित कर सकता है।


7
धन्यवाद ... यह देखना कठिन है कि स्वीकृत उत्तर कैसे iterऔर किसके बीच अंतर को स्पष्ट करता है into_iter
MMW

बिलकुल वही, जिसकी मुझे तलाश थी!
साइरसमीथ

6

.into_iter()एक सरणी में ही है, लेकिन केवल के लिए लागू नहीं है &[]। की तुलना करें:

impl<'a, T> IntoIterator for &'a [T]
    type Item = &'a T

साथ में

impl<T> IntoIterator for Vec<T>
    type Item = T

चूंकि IntoIteratorकेवल परिभाषित किया गया है &[T], स्लाइस को उसी तरह से गिराया नहीं जा सकता Vecजब आप मूल्यों का उपयोग करते हैं। (मान नहीं निकाले जा सकते)

अब, ऐसा क्यों है कि मामला एक अलग मुद्दा है, और मैं खुद सीखना चाहूंगा। अटकलबाजी: सरणी डेटा ही है, टुकड़ा केवल इसमें एक दृश्य है। व्यवहार में आप सरणी को किसी अन्य फ़ंक्शन में मान के रूप में स्थानांतरित नहीं कर सकते, बस इसे देखें, ताकि आप वहां इसका उपभोग न कर सकें।


IntoIteratorके लिए भी लागू किया जाता है &'a mut [T], इसलिए यह ऑब्जेक्ट्स को सरणी से बाहर ले जा सकता है । मुझे लगता है कि यह इस तथ्य से संबंधित है कि रिटर्न संरचना IntoIter<T>में आजीवन तर्क Iter<'a, T>नहीं होता है, इसलिए पूर्व एक टुकड़ा नहीं रख सकता है।
रॉडरिगो

mutइसका मतलब है कि आप मूल्यों को बदल सकते हैं, न कि आप उन्हें बाहर निकाल सकते हैं।
विराटपुर

@rodrigo let mut a = ["abc".to_string()]; a.into_iter().map(|x| { *x });=> "त्रुटि: उधार ली गई सामग्री से बाहर नहीं जा सकते"
viraptor

हाँ, मुझे लगता है कि आप सही हैं और मूल्यों को सरणी से स्थानांतरित नहीं किया जा सकता है। हालांकि, मुझे अभी भी लगता है कि ArrayIntoIterपुस्तकालय के हिस्से के रूप में असुरक्षित जंग का उपयोग करके एक प्रकार की संरचना को लागू करना संभव होना चाहिए ... शायद इसके लायक नहीं, जैसा कि आप Vecवैसे भी उन मामलों के लिए उपयोग करना चाहिए ।
कृतिगो

इसलिए मुझे समझ में नहीं आता ... क्या यह कारण है कि array.into_iterरिटर्न &T- क्योंकि यह स्वचालित रूप से इसे बदलने के लिए जादू कर रहा है &array.into_iter- और यदि हां, तो मुझे समझ में नहीं आता है कि मूविंग वैल्यू के साथ क्या करना है या मूविंग वैल्यू नहीं है। या जैसा कि @rodrigo ने कहा है, कि आपको संदर्भ केवल इसलिए मिलता है क्योंकि (किसी कारण से) आप सरणियों से मानों को स्थानांतरित नहीं कर सकते हैं ? अभी भी बहुत उलझन में है।
विटिरल

2

मुझे लगता है कि कुछ और स्पष्ट करने के लिए कुछ है। संग्रह प्रकार, जैसे कि Vec<T>और VecDeque<T>, into_iterविधि है कि पैदावार Tक्योंकि वे लागू करते हैं IntoIterator<Item=T>। एक प्रकार का निर्माण करने के लिए हमें रोकने के लिए कुछ भी नहीं है Foo<T>अगर जो अधिक पुनरावृत्त है, तो यह Tएक और प्रकार नहीं बल्कि उपज देगा U। वह है, Foo<T>लागू होना IntoIterator<Item=U>

वास्तव में, कुछ उदाहरण हैं std: &Path लागू करना IntoIterator<Item=&OsStr> और &UnixListener लागू करना IntoIterator<Item=Result<UnixStream>>


into_iterऔर के बीच का अंतरiter

into_iterऔर के बीच के अंतर पर मूल प्रश्न पर वापस जाएं iter। जैसा कि अन्य ने बताया है, अंतर यह है कि into_iterएक आवश्यक विधि है, IntoIteratorजिसमें किसी भी प्रकार का निर्दिष्ट पैदावार मिल सकती है IntoIterator::Item। आमतौर पर, यदि एक प्रकार का IntoIterator<Item=I>अधिवेशन, इसके अधिवेशन के भी दो तदर्थ तरीके हैं: iterऔर iter_mutजो क्रमशः उपज &Iऔर &mut I

इसका तात्पर्य यह है कि हम एक ऐसा फंक्शन बना सकते हैं जिसमें एक प्रकार मिलता है जिसमें एक into_iterविधि है (यानी यह एक चलने योग्य है) एक ट्रेस बाउंड का उपयोग करके:

fn process_iterable<I: IntoIterator>(iterable: I) {
    for item in iterable {
        // ...
    }
}

हालांकि, हम नहीं कर सकते हैं * एक विशेषता है करने के लिए एक प्रकार की आवश्यकता होती है करने के लिए बाध्य का उपयोग iterविधि या iter_mut, विधि, क्योंकि वे सिर्फ सम्मेलनों कर रहे हैं। हम कह सकते हैं कि into_iterअधिक व्यापक रूप से प्रयोग करने योग्य iterया से अधिक है iter_mut

करने के लिए विकल्प iterऔरiter_mut

निरीक्षण करने के लिए एक और दिलचस्प यह iterहै कि पैदावार करने वाले इट्रेटर प्राप्त करने का एकमात्र तरीका नहीं है &T। परंपरा के मुताबिक (फिर), संग्रह प्रकार SomeCollection<T>में stdजो है iterविधि को भी अपने अपरिवर्तनीय संदर्भ प्रकार &SomeCollection<T>लागू IntoIterator<Item=&T>। उदाहरण के लिए, &Vec<T> लागू होता है IntoIterator<Item=&T> , इसलिए यह हमें इसे पुन &Vec<T>: व्यवस्थित करने में सक्षम बनाता है :

let v = vec![1, 2];

// Below is equivalent to: `for item in v.iter() {`
for item in &v {
    println!("{}", item);
}

यदि उस दोनों में v.iter()समान है , तो &vलागू IntoIterator<Item=&T>क्यों होता है, तो दोनों क्यों प्रदान करते हैं? यह एर्गोनॉमिक्स के लिए है। में forछोरों, यह उपयोग करने के लिए एक सा अधिक संक्षिप्त है &vकी तुलना में v.iter(); लेकिन अन्य मामलों में, v.iter()की तुलना में बहुत स्पष्ट है (&v).into_iter():

let v = vec![1, 2];

let a: Vec<i32> = v.iter().map(|x| x * x).collect();
// Although above and below are equivalent, above is a lot clearer than below.
let b: Vec<i32> = (&v).into_iter().map(|x| x * x).collect();

इसी तरह, forछोरों में, v.iter_mut()इसके साथ प्रतिस्थापित किया जा सकता है &mut v:

let mut v = vec![1, 2];

// Below is equivalent to: `for item in v.iter_mut() {`
for item in &mut v {
    *item *= 2;
}

जब एक प्रकार के लिए प्रदान करने (लागू करने) into_iterऔर iterतरीके

यदि टाइप का केवल एक ही "तरीका" है जो इसे खत्म कर देता है, तो हमें दोनों को लागू करना चाहिए। हालांकि, अगर दो तरीके या अधिक हैं, तो इसे खत्म किया जा सकता है, हमें इसके बजाय प्रत्येक तरीके के लिए एक तदर्थ विधि प्रदान करनी चाहिए।

उदाहरण के लिए, Stringन तो प्रदान करता है और न into_iterही iterक्योंकि इसे पुनरावृत्त करने के दो तरीके हैं: बाइट्स में अपने प्रतिनिधित्व को पुनरावृत्त करना या वर्णों में इसके प्रतिनिधित्व को पुनरावृत्त करना। इसके बजाय, यह दो तरीके प्रदान करता है: bytesबाइट्स charsके पुनरावृत्ति के लिए और वर्णों को पुनरावृत्त करने के लिए, iterविधि के विकल्प के रूप में ।


* ठीक है, तकनीकी रूप से हम इसे एक विशेषता बनाकर कर सकते हैं। लेकिन तब हमें implउस प्रकार के गुण की आवश्यकता होती है जिसका हम उपयोग करना चाहते हैं। इस बीच, stdपहले से ही लागू कई प्रकार IntoIterator

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.