Rust आपको स्वयं पर संदर्भ संग्रहीत करने की अनुमति क्यों नहीं देता: उदाहरणों के साथ समझें
\n\nएक स्थिति की कल्पना करें: आप Rust में एक प्रोग्राम लिख रहे हैं, और आपको एक ऐसी संरचना बनाने की आवश्यकता है जो कुछ डेटा संग्रहीत करती है, साथ ही उसी डेटा का एक संदर्भ भी। तार्किक है, है ना? बिल्कुल! लेकिन Rust कंपाइलर अचानक एक त्रुटि देता है, और आप हैरान रह जाते हैं। परिचित लगता है? यह प्रश्न Stack Overflow पर सबसे लोकप्रिय प्रश्नों में से एक है (हज़ारों बार देखा गया), और आज हम इसे शुरू से अंत तक समझेंगे।
\n\nइस चरण-दर-चरण ट्यूटोरियल में, हम न केवल यह समझेंगे कि Rust में एक ही संरचना में मान और संदर्भ क्यों नहीं रख सकते, बल्कि इस सीमा को सुरक्षित तरीकों से पार करना भी सीखेंगे। चलिए शुरू करते हैं!
\n\nसमस्या: एक भोली कोशिश
\n\nमान लीजिए, हम एक ऐसी संरचना बनाना चाहते हैं जो एक स्ट्रिंग और उसका पहला अक्षर (पहले वर्ण का संदर्भ) संग्रहीत करती है। कोड में यह इस तरह दिखता है:
\n\nstruct MyStruct {\n data: String,\n first_char: &str, // data का संदर्भ\n}\n\nfn main() {\n let s = String::from("Hello");\n let first = &s[0..1]; // पहले वर्ण का संदर्भ\n \n let my_struct = MyStruct {\n data: s,\n first_char: first, // संदर्भ को सहेजने का प्रयास\n };\n}\n\n\nकंपाइलर एक त्रुटि देता है जो कई शुरुआती लोगों को भ्रमित करती है। आइए समझें कि वास्तव में क्या गलत हुआ।
\n\nRust स्व-संदर्भित संरचनाओं को क्यों प्रतिबंधित करता है?
\n\nसमस्या की जड़ Rust की ownership (स्वामित्व) और borrowing (उधार) प्रणाली में है। जब आप मान s को data क्षेत्र में move (स्थानांतरित) करते हैं, तो यह भौतिक रूप से मेमोरी में एक नए स्थान पर कॉपी हो जाता है। संदर्भ first अभी भी पुराने पते की ओर इशारा करता है, जो अब अमान्य है।
Rust में, प्रत्येक संदर्भ अपने पूरे अस्तित्व के दौरान मान्य होना चाहिए। Rust स्व-संदर्भित संरचनाएँ इस नियम का उल्लंघन करती हैं, क्योंकि संदर्भ और मान एक ही ऑब्जेक्ट में रहते हैं, और संरचना के स्थानांतरित होने पर संदर्भ dangling reference (लटकता हुआ संदर्भ) बन जाता है।
\n\nअंदर क्या होता है?
\n\nजब आप ऐसा कोड लिखते हैं:
\n\nlet s = String::from("Hello");\nlet first = &s[0..1];\nlet my_struct = MyStruct { data: s, first_char: first };\n\n\nनिम्नलिखित होता है:
\n- \n
sके पास हीप में स्ट्रिंग "Hello" का स्वामित्व है। \n first— इस स्ट्रिंग के एक भाग का संदर्भ है। \n - संरचना बनाते समय
data: s— स्ट्रिंग का स्वामित्व संरचना को स्थानांतरित हो जाता है। स्ट्रिंग मेमोरी में स्थानांतरित हो सकती है। \n - संदर्भ
firstअभी भी पुराने पते की ओर इशारा करता है — यह एक dangling reference (लटकता हुआ संदर्भ) है। Rust इसे अनुमति नहीं दे सकता। \n
Rust का Borrow checker इस संभावित असुरक्षा को देखता है और संकलन चरण में कोड को ब्लॉक कर देता है। यह कोई बग नहीं, बल्कि एक विशेषता है जो रनटाइम में कई समस्याओं से बचाती है।
\n\nवास्तविक परिदृश्य जहाँ स्व-संदर्भित संरचनाओं की आवश्यकता होती है
\n\nप्रतिबंध के बावजूद, ऐसी संरचनाएँ उपयोगी हो सकती हैं। यहाँ विशिष्ट मामले हैं:
\n\n- \n
- पार्सर और AST: जब ट्री के नोड एक-दूसरे को संदर्भित करते हैं। \n
- गेम इंजन: ऐसी संस्थाएँ जिनमें अपने घटकों के संदर्भ होते हैं। \n
- नेटवर्क प्रोटोकॉल: आंतरिक पॉइंटर्स वाले बफ़र। \n
- प्लगइन सिस्टम: जब कोई ऑब्जेक्ट अपने कॉन्फ़िगरेशन का संदर्भ रखता है। \n
अच्छी खबर: इस सीमा को पार करने के सुरक्षित तरीके हैं!
\n\nसमाधान 1: संदर्भों के बजाय इंडेक्स का उपयोग करना (सबसे आसान तरीका)
\n\nसबसे आसान और सुरक्षित तरीका है कि संदर्भ के बजाय इंडेक्स या कुंजी संग्रहीत करें। &str के बजाय usize (पहले वर्ण की स्थिति) संग्रहीत करें।
struct MyStruct {\n data: String,\n first_char_index: usize, // संदर्भ के बजाय स्थिति संग्रहीत करें\n}\n\nimpl MyStruct {\n fn first_char(&self) -> &