iter बनाम into_iter: Rust में इटरेशन के दिग्गजों की लड़ाई
\n\nयदि आपने कभी Rust में किसी वेक्टर पर लूप लिखा है, तो आपने निश्चित रूप से तीन समान भाइयों का सामना किया होगा: iter(), into_iter() और iter_mut()। पहली नज़र में, ये सभी एक ही काम करते हैं - तत्वों के माध्यम से जाने की अनुमति देते हैं। लेकिन उनके बीच का अंतर जितना लगता है उससे कहीं अधिक गहरा है, और यह Rust के मूल में - स्वामित्व प्रणाली में छिपा है।
कल्पना करें कि आप एक बरिस्ता हैं, और आपका संग्रह कॉफी बीन्स है। iter() आपको बीन्स को देखने, उन्हें सूंघने की अनुमति देता है, लेकिन छूने की नहीं। into_iter() तब होता है जब आप बीन्स लेते हैं, उन्हें पीसते हैं और एस्प्रेसो बनाते हैं, जिसके बाद बीन्स गायब हो जाते हैं। और iter_mut() - आप न केवल देख सकते हैं, बल्कि बैग में ही बीन्स को पीस सकते हैं, उनका आकार बदल सकते हैं।
आज हम iter बनाम into_iter को उसी तरह समझेंगे जैसे Stack Overflow पर समझाया जाता है, लेकिन जीवंत उदाहरणों और हुड के नीचे गहराई से जाने के साथ। चलिए शुरू करते हैं!
\n\nRust में इटरेटर क्या है?
\n\nइटरेटर एक ऐसी वस्तु है जो जानती है कि किसी संग्रह से क्रमिक रूप से तत्व कैसे प्राप्त करें। Rust में इटरेटर आलसी होते हैं: वे तब तक कुछ नहीं करते जब तक आप next() को कॉल नहीं करते। लेकिन मुख्य बात यह है कि इटरेशन की प्रत्येक विधि डेटा के स्वामित्व के साथ अलग-अलग व्यवहार करती है।
यहाँ तीन मुख्य दृष्टिकोण हैं:
\n- \n
iter()- तत्वों को उधार लेता है (स्वामित्व नहीं लेता) \n into_iter()- संग्रह को उपभोग करता है (स्वामित्व लेता है) \n iter_mut()- बदलने की क्षमता के साथ उधार लेता है \n
आइए कोड देखें। मान लीजिए हमारे पास नामों का एक वेक्टर है:
\n\nlet names = vec!["अन्ना".to_string(), "बोरिस".to_string(), "विक्टर".to_string()];\n\nउदाहरण 1: iter() - केवल देखना
\n\nfn main() {\n let names = vec!["अन्ना".to_string(), "बोरिस".to_string(), "विक्टर".to_string()];\n \n // iter() &String (संदर्भ) लौटाता है\n for name in names.iter() {\n println!("नमस्ते, {}!", name);\n }\n \n // names अभी भी उपलब्ध है!\n println!("वेक्टर जीवित है: {:?}", names);\n}\n\nध्यान दें: लूप के बाद हम आराम से names का उपयोग करते हैं। क्यों? क्योंकि iter() ने प्रत्येक तत्व का संदर्भ लौटाया। स्वामित्व वेक्टर के पास रहा। यह सुरक्षित और पूर्वानुमानित है।
उदाहरण 2: into_iter() - पुल जलाना
\n\nfn main() {\n let names = vec!["अन्ना".to_string(), "बोरिस".to_string(), "विक्टर".to_string()];\n \n // into_iter() String लौटाता है (स्वामित्व स्थानांतरित होता है)\n for name in names.into_iter() {\n println!("अलविदा, {}!", name);\n }\n \n // त्रुटि! names अब मौजूद नहीं है\n // println!("वेक्टर जीवित है: {:?}", names); // ❌ स्थानांतरित मान का उधार\n}\n\nयह है मुख्य अंतर। into_iter() संग्रह को उपभोग करता है। प्रत्येक तत्व लूप में स्थानांतरित हो जाता है, और मूल वेक्टर अमान्य हो जाता है। यदि आपको आगे उपयोग के लिए संग्रह को संरक्षित करने की आवश्यकता है - into_iter() आपका विकल्प नहीं है।
उदाहरण 3: iter_mut() - बिना नष्ट किए बदलना
\n\nfn main() {\n let mut names = vec!["अन्ना".to_string(), "बोरिस".to_string(), "विक्टर".to_string()];\n \n // iter_mut() &mut String (परिवर्तनीय संदर्भ) लौटाता है\n for name in names.iter_mut() {\n name.push_str(" (अतिथि)");\n }\n \n println!("बदला हुआ वेक्टर: {:?}", names);\n // आउटपुट: ["अन्ना (अतिथि)", "बोरिस (अतिथि)", "विक्टर (अतिथि)"]\n}\n\nयहाँ हम तत्वों को उनके स्थान पर बदलते हैं, लेकिन स्वामित्व नहीं लेते। परिवर्तनों के लिए आदर्श।
\n\nहुड के नीचे: प्रत्येक विधि क्या लौटाती है?
\n\niter बनाम into_iter को वास्तव में समझने के लिए, आइए मानक पुस्तकालय में देखें। वेक्टर Vec<T> के लिए:
- \n
iter()std::slice::Iter<T>लौटाता है - यहIterator<Item = &T>को लागू करता है