Rust में Option<String> को Option<&str> में बिना दर्द के कैसे बदलें

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

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

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

आप यहाँ क्यों हैं? ईमानदारी से स्वीकार करें

\n\n

आप Rust में कोड लिख रहे हैं, और अचानक एक दीवार से टकरा जाते हैं। आपके पास Option<String> है — एक ऐसा मान जो हो सकता है या नहीं भी हो सकता है। और जिस फ़ंक्शन को आप कॉल करना चाहते हैं, उसे Option<&str> चाहिए। और कंपाइलर आपको तिरस्कार भरी नज़र से देखता है, एक ऐसी त्रुटि देता है जिससे आप लैपटॉप बंद करके चाय पीने जाना चाहते हैं।

\n\n

चिंता न करें। यह स्थिति इतनी सामान्य है कि Stack Overflow पर "Converting from Option<String> to Option<&str>" प्रश्न को हज़ारों बार देखा गया है। आप अकेले नहीं हैं।

\n\n

इस लेख में, हम समझेंगे कि यह रूपांतरण इतने सारे प्रश्न क्यों उत्पन्न करता है, और — सबसे महत्वपूर्ण — इसे सही तरीके से कैसे करें। बिना जादू के, बिना अनावश्यक मेमोरी कॉपी के, और पूरी समझ के साथ कि हुड के नीचे क्या हो रहा है।

\n\n

समस्या: आप इसे सीधे क्यों नहीं बदल सकते?

\n\n

पहले — प्रकारों पर एक त्वरित नज़र।

\n\n
    \n
  • String — एक स्वामित्व वाला प्रकार है। यह हीप में डेटा का मालिक है और इसे मुक्त करने के लिए जिम्मेदार है।
  • \n
  • &str — एक स्ट्रिंग स्लाइस का संदर्भ है। यह डेटा को उधार लेता है, उसका मालिक नहीं है।
  • \n
\n\n

और यहाँ मज़ा शुरू होता है। Option<String> — एक संभावित स्ट्रिंग है जिसके आप मालिक हैं। Option<&str> — एक संभावित स्ट्रिंग संदर्भ है।

\n\n

समस्या यह है कि आप Option के अंदर के मान का संदर्भ लेकर उसे बाहर नहीं दे सकते, यदि Option अस्थायी है। संदर्भ को किसी चीज़ की ओर इशारा करना चाहिए, और उस "चीज़" को पर्याप्त समय तक जीवित रहना चाहिए।

\n\n

आइए एक शुरुआती की विशिष्ट गलती देखें:

\n\n
fn process(value: Option<String>) {\n    // त्रुटि! cannot return reference to temporary value\n    let ref_value: Option<&str> = value.as_ref().map(|s| s.as_str());\n    // या और भी सीधे:\n    let ref_value: Option<&str> = Some(value.unwrap().as_str()); // बूम!\n}
\n\n

कंपाइलर लाल रंग में फट जाता है। क्यों? क्योंकि value स्ट्रिंग का मालिक है। जब आप इससे &str लेने का प्रयास करते हैं, तो संदर्भ को value से अधिक समय तक जीवित नहीं रहना चाहिए। और यदि value एक अस्थायी ऑब्जेक्ट है (जैसे, किसी फ़ंक्शन कॉल का परिणाम), तो संदर्भ लटकता हुआ (dangling reference) बन जाता है।

\n\n

समाधान #1: as_deref() — आपका नया सबसे अच्छा दोस्त

\n\n

Option<String> को Option<&str> में बदलने का सबसे सुंदर तरीका as_deref() विधि है।

\n\n

यह कैसे काम करता है? as_deref() दो काम करता है:

\n
    \n
  1. यह &Option<T> लेता है और इसे Option<&T> में बदल देता है (यह as_ref() करता है)।
  2. \n
  3. फिर यह आंतरिक मान पर Deref लागू करता है, &String को &str में बदल देता है।
  4. \n
\n\n

कोड में यह इस तरह दिखता है:

\n\n
fn main() {\n    let my_string: Option<String> = Some(String::from("नमस्ते, Rust!"));\n    \n    // एक पंक्ति का जादू:\n    let my_str_ref: Option<&str> = my_string.as_deref();\n    \n    match my_str_ref {\n        Some(s) => println!("स्ट्रिंग: {}", s),\n        None => println!("स्ट्रिंग नहीं है"),\n    }\n    // my_string अभी भी जीवित और स्वस्थ है!\n    println!("मूल स्ट्रिंग: {:?}", my_string);\n}
\n\n

ध्यान दें: my_string डेटा का मालिक बना रहता है। हमने केवल इसकी सामग्री का संदर्भ लिया है। इसका मतलब है कि my_str_ref तभी तक जीवित रहता है जब तक my_string जीवित है।

\n\n

यदि Option खाली है तो क्या होगा?

\n

यह बहुत सरल है:

\n\n
fn main() {\n    let empty: Option<String> = None;\n    let result: Option<&str> = empty.as_deref();\n    println!("{:?}", result); // None\n}
\n\n

कोई पैनिक नहीं, कोई क्रैश नहीं। घड़ी की तरह काम करता है।

ब्लॉग

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