Rust में इटरेटर लौटाना: प्रदर्शन के रहस्य और zero-cost एब्स्ट्रैक्शन

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

इटरेटर लौटाना एक चुनौती क्यों है

\n\n

क्या आपने कभी Rust में कोई ऐसा फंक्शन लिखा है जिसे इटरेटर की चेन के माध्यम से प्रोसेस किया गया कलेक्शन लौटाना हो? यदि हाँ, तो आपने निश्चित रूप से इस प्रश्न का सामना किया होगा: "मुझे किस प्रकार का रिटर्न टाइप देना चाहिए?" तार्किक रूप से fn get_data() -> Iterator लिखना सही लगता है, लेकिन कंपाइलर तुरंत एक त्रुटि देता है: "the trait `Iterator` cannot be made into an object".

\n\n

यह समस्या इतनी सामान्य है कि Stack Overflow पर प्रश्न "What is the correct way to return an Iterator (or any other trait)?" को हजारों बार देखा जा चुका है। और यह आश्चर्यजनक नहीं है — सही विकल्प न केवल कोड की सुविधा को प्रभावित करता है, बल्कि प्रदर्शन को भी प्रभावित करता है। इस लेख में, हम Rust में इटरेटर लौटाने के सभी तरीकों, उनके फायदे और नुकसान, और सबसे महत्वपूर्ण बात, बिना किसी कारण के प्रदर्शन कैसे न खोएँ, का विश्लेषण करेंगे।

\n\n

यह लेख pythonlib.ru के लिए लिखा गया है — एक शैक्षिक वेबसाइट, जहाँ हम लोकप्रिय भाषाओं के अंदरूनी कामकाज को देखने से नहीं डरते। Rust, अपने zero-cost एब्स्ट्रैक्शन के साथ, हमें ऐसा कोड लिखने का एक अनूठा अवसर देता है जो एक साथ सुरुचिपूर्ण और तेज़ हो। लेकिन केवल तभी जब हम जानते हैं कि इसके उपकरणों का सही तरीके से उपयोग कैसे किया जाए।

\n\n

समस्या: ट्रेट्स का कोई आकार नहीं होता

\n\n

Rust में, ट्रेट्स इंटरफ़ेस हैं, लेकिन Java या Go के विपरीत, वे ज्ञात आकार वाले प्रकार नहीं हैं। कंपाइलर को यह जानना होता है कि रिटर्न वैल्यू कितनी मेमोरी लेती है ताकि स्टैक पर जगह आवंटित की जा सके। और इटरेटर के एक विशिष्ट कार्यान्वयन का आकार (जैसे, std::iter::Map या std::iter::Filter) भिन्न हो सकता है।

\n\n

इसलिए, सीधे Iterator लौटाना संभव नहीं है। हमें निम्नलिखित पैटर्न में से एक चुनना होता है:

\n\n
    \n
  • स्टैटिक डिस्पैचिंग — impl Iterator (एक विशिष्ट प्रकार लौटाना)
  • \n
  • डायनामिक डिस्पैचिंग — Box<dyn Iterator> (प्रकार मिटा दिया जाता है)
  • \n
  • Enum dispatch — सभी संभावित इटरेटर के लिए अपना खुद का enum
  • \n
  • जेनेरिक्स — एक फंक्शन जो सामान्यीकृत प्रकारों को स्वीकार और लौटाता है
  • \n
\n\n

प्रत्येक दृष्टिकोण की अपनी लागत होती है। आइए वास्तविक उदाहरणों के साथ उनका विश्लेषण करें।

\n\n

तरीका 1: impl Iterator — स्वर्ण मानक

\n\n

सबसे सरल और सबसे अधिक प्रदर्शन करने वाला तरीका रिटर्न टाइप में impl Trait का उपयोग करना है। यह सिंटैक्टिक शुगर है जो कंपाइलर को बताता है: "मैं ट्रेट को लागू करने वाला कुछ विशिष्ट प्रकार लौटाऊँगा, लेकिन आप स्वयं इसका अनुमान लगाइए।"

\n\n
fn get_numbers() -> impl Iterator<Item = i32> {\n    (0..10).map(|x| x * 2)\n}\n\nfn main() {\n    for num in get_numbers() {\n        println!("{}", num);\n    }\n}
\n\n

लाभ:

\n
    \n
  • अधिकतम प्रदर्शन — स्टैटिक डिस्पैचिंग, कोई वर्चुअल कॉल नहीं
  • \n
  • कंपाइलर कोड को इनलाइन कर सकता है और अनुकूलन लागू कर सकता है
  • \n
  • परिणामी बाइनरी का न्यूनतम आकार
  • \n
\n\n

नुकसान:

\n
    \n
  • लौटाया गया प्रकार एक समान होना चाहिए — एक मामले में Map और दूसरे में Filter नहीं लौटाया जा सकता
  • \n
  • प्रकार बहुत जटिल हो सकता है (जैसे, Map<Filter<...>>), जिससे कंपाइलर त्रुटियों को पढ़ना मुश्किल हो जाता है
  • \n
  • स्ट्रक्चर या वेक्टर में संग्रहीत नहीं किया जा सकता — केवल फंक्शन में
  • \n
\n\n

यह तरीका 90% मामलों के लिए आदर्श है। यदि आपका फंक्शन हमेशा एक ही इटरेटर चेन लौटाता है — तो बिना किसी हिचकिचाहट के impl Iterator का उपयोग करें।

\n\n

तरीका 2: Box<dyn Iterator> — प्रदर्शन की कीमत पर लचीलापन

\n\n

जब आपको शर्तों के आधार पर विभिन्न प्रकार के इटरेटर लौटाने की आवश्यकता होती है (उदाहरण के लिए, कमांड लाइन तर्कों को पार्स करते समय), तो Box<dyn Iterator> के माध्यम से डायनामिक डिस्पैचिंग मदद करता है।

\n\n
fn get_data(use_filter: bool) -> Box<dyn Iterator<Item = i32>> {\n    let data = vec![1, 2, 3, 4, 5];\n    if use_filter {\n                

ब्लॉग

पुस्तक अनुशंसाएँ