परिचय: जब Rust आपको "समझ नहीं पाता"
\nआप Rust में कोड लिख रहे हैं। सब कुछ ठीक चल रहा है। कंपाइलर चुप है। आपको लगता है कि आप मेमोरी के राजा हैं। और फिर — धमाका! — यह एरर आती है:
\nerror[E0507]: cannot move out of borrowed content\n --> src/main.rs:10:9\n |\n10 | let value = self.data;\n | ^^^^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait\n\nया इसकी करीबी रिश्तेदार:
\nerror[E0507]: cannot move out of `*self` which is behind a shared reference\n\nअगर आप नए हैं, तो यह किसी जादुई श्राप जैसा लगता है। अगर अनुभवी हैं, तो आप जानते हैं कि यह Borrow Checker (उधार जांचकर्ता) का एक और सबक है।
\nइस लेख में, हम समझेंगे कि ये एरर क्या मतलब रखती हैं, Rust इतना सख्त क्यों है, और — सबसे महत्वपूर्ण — लाइव कोड उदाहरणों के साथ इन्हें कैसे ठीक करें। यह उबाऊ थ्योरी नहीं, बल्कि ownership और borrowing की दुनिया में जीवित रहने की एक प्रैक्टिकल गाइड है।
\n\nमुख्य बातें: Ownership, Borrowing और "Move"
\nगहराई में जाने से पहले, Rust के तीन स्तंभों को याद कर लें:
\n- \n
- Ownership (स्वामित्व): Rust में हर वैल्यू का एक ही मालिक होता है। \n
- Borrowing (उधार लेना): आप रेफरेंस (&T — अपरिवर्तनीय, &mut T — परिवर्तनीय) के ज़रिए वैल्यू को "उधार" ले सकते हैं, बिना ownership लिए। \n
- Move (स्थानांतरण): जब आप किसी वैल्यू को नए वेरिएबल में असाइन करते हैं या बिना & के फंक्शन में भेजते हैं, तो ownership स्थानांतरित हो जाती है। मूल वेरिएबल अमान्य हो जाता है। \n
cannot move out of borrowed content एरर तब आती है जब आप उस वैल्यू को स्थानांतरित करने की कोशिश करते हैं जिसका आपके पास केवल रेफरेंस (&T) है। Rust इसे मना करता है क्योंकि स्थानांतरण के बाद रेफरेंस "लटकता हुआ" (dangling pointer) हो जाएगा। और Rust, जैसा कि आप जानते हैं, ऐसी चीज़ों को माफ नहीं करता।
परिदृश्य 1: &self के ज़रिए स्ट्रक्चर के फील्ड को स्थानांतरित करने की कोशिश
\nसबसे आम मामला। आपके पास एक स्ट्रक्चर है, और आप उसके किसी फील्ड को एक मेथड से वापस करना चाहते हैं जो &self लेता है।
एरर वाला कोड
\nstruct User {\n name: String,\n age: u32,\n}\n\nimpl User {\n // name को "हमेशा के लिए" देने की कोशिश\n fn give_name(&self) -> String {\n self.name // एरर!\n }\n}\n\nfn main() {\n let user = User { name: "Ravi".to_string(), age: 25 };\n let name = user.give_name();\n println!("{}", name);\n}\n\nकंपाइलर कहेगा:
\nerror[E0507]: cannot move out of `self.name` which is behind a shared reference\n\nक्यों? self एक &User है। हम self के मालिक नहीं हैं, हमने इसे केवल उधार लिया है। self.name (टाइप String, जो Copy ट्रेट को इम्प्लीमेंट नहीं करता) को स्थानांतरित करने का मतलब है कि मेथड कॉल के बाद मालिक (user) अपना फील्ड खो देगा। लेकिन रेफरेंस &self अभी भी मौजूद है! Rust हमें इस आपदा से बचाता है।
इसे कैसे ठीक करें?
\nआपके काम के अनुसार तीन मुख्य तरीके हैं।
\n\nतरीका 1: क्लोनिंग (सबसे आसान, लेकिन हमेशा कुशल नहीं)
\nअगर आपको वैल्यू चाहिए, रेफरेंस नहीं, और आप कॉपी करने की कीमत चुकाने को तैयार हैं:
\nfn give_name(&self) -> String {\n self.name.clone() // काम करता है! एक कॉपी बनाता है।\n}\n\nनुकसान: String के लिए clone() हीप पर पूरे डेटा की कॉपी बनाता है। बड़े स्ट्रिंग्स पर यह महंगा हो सकता है।
तरीका 2: रेफरेंस वापस करना (सिग्नेचर बदलना)
\nअगर कॉल करने वाले कोड के लिए फील्ड का रेफरेंस काफी है:
\nfn give_name(&self) -> &String {\n &self.name // रेफरेंस वापस करता है, कोई स्थानांतरण नहीं\n}\n\nअब हम स्थानांतरित नहीं कर रहे, बल्कि उधार ले रहे हैं। सब ठीक है। कॉल करने वाला कोड &String प्राप्त करेगा।