Rust में Option से Result: मैक्रोज़ के बिना ट्यूटोरियल

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

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

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

Option को Result में बदलने के लिए मैक्रोज़ लिखकर क्यों थक गए हैं?

\n

आप Rust में लिख रहे हैं, और अचानक महसूस करते हैं: आपके पास Option<T> है, लेकिन आपको Result<T, E> चाहिए। यह एक छोटी सी बात लगती है। लेकिन अगर आप शुरुआती हैं, तो पहला विचार आता है: "शायद एक मैक्रो चाहिए!" या आप पहले से ही एक अनुभवी डेवलपर हैं, लेकिन हर बार वही लिखते हैं: match option { Some(v) => Ok(v), None => Err("error") }। मान लीजिए, यह थका देने वाला है।

\n

Stack Overflow पर प्रश्न "क्या मैक्रो के बिना Option को Result में बदलने को सरल बनाने का कोई तरीका है?" ने हज़ारों बार देखा गया है। यह कोई संयोग नहीं है: यह समस्या Rust के साथ काम करने वाले हर किसी से परिचित है। लेकिन अच्छी खबर यह है कि इसका एक समाधान है, और यह आश्चर्यजनक रूप से सरल है। इस ट्यूटोरियल में, हम बुनियादी से लेकर सुरुचिपूर्ण तक, बिना एक भी मैक्रो के सभी तरीकों पर चर्चा करेंगे।

\n

हम केवल उत्तर नहीं देंगे - हम दिखाएंगे कि Rust डेवलपर की तरह कैसे सोचें। चलिए शुरू करते हैं!

\n\n

Rust में Option और Result क्या हैं?

\n

रूपांतरण से पहले, आइए सुनिश्चित करें कि हम एक ही पृष्ठ पर हैं।

\n
    \n
  • Option<T> — एक प्रकार है जो या तो Some(T) (मान मौजूद है) या None (मान मौजूद नहीं है) हो सकता है। इसका उपयोग तब किया जाता है जब मान का न होना एक सामान्य स्थिति हो (जैसे, संग्रह में कोई तत्व खोजना)।
  • \n
  • Result<T, E> — एक प्रकार है जो या तो Ok(T) (सब कुछ ठीक है) या Err(E) (कोई त्रुटि हुई) हो सकता है। इसका उपयोग उन संक्रियाओं के लिए किया जाता है जो विफल हो सकती हैं (जैसे, फ़ाइल पढ़ना)।
  • \n
\n

समस्या: कभी-कभी आपके पास Option होता है, लेकिन प्रोग्राम के तर्क के अनुसार मान का न होना एक त्रुटि है। यहीं पर रूपांतरण की आवश्यकता होती है।

\n\n

बुनियादी तरीका: match (लेकिन आप यह पहले से जानते हैं)

\n

सबसे स्पष्ट और शुरुआती लोगों द्वारा अक्सर उपयोग किया जाने वाला तरीका match है। हाँ, यह काम करता है, लेकिन यह शब्दाडंबरपूर्ण है:

\n
fn get_user_name(id: u32) -> Option<String> {\n    // ... कुछ तर्क\n    if id == 1 { Some("Alice".to_string()) } else { None }\n}\n\nfn main() {\n    let user_id = 2;\n    let name = match get_user_name(user_id) {\n        Some(name) => Ok(name),\n        None => Err("User not found"),\n    };\n    println!("{:?}", name); // Err("User not found")\n}
\n

यह कोड सही है, लेकिन अगर प्रोजेक्ट में ऐसे दर्जनों रूपांतरण हैं, तो आप match लिखते-लिखते थक जाएंगे। साथ ही, गलती करना और None को संभालना भूलना आसान है। कुछ अधिक संक्षिप्त चाहिए।

\n\n

ok_or विधि: आपका नया सबसे अच्छा दोस्त

\n

Rust की मानक लाइब्रेरी Option के लिए ok_or विधि प्रदान करती है। यह ठीक वही करता है जो हमें चाहिए: Some(v) को Ok(v) में और None को Err(error) में बदलता है, जहाँ error वह मान है जो आप पास करते हैं।

\n
fn main() {\n    let user_id = 2;\n    let name = get_user_name(user_id).ok_or("User not found");\n    println!("{:?}", name); // Err("User not found")\n}
\n

बस एक पंक्ति! लेकिन एक बारीक बात है: ok_or स्वामित्व वाला मान (owned value) लेता है। यदि आप एक स्ट्रिंग लिटरल पास करते हैं, जैसा कि उदाहरण में है, तो यह काम करता है, क्योंकि &str Into<String> को लागू करता है। लेकिन अगर आपको कोई त्रुटि पास करनी है जो पहले से कहीं संग्रहीत है, तो इससे अनावश्यक कॉपी हो सकती है।

\n

ऐसे मामलों के लिए ok_or_else है — यह एक क्लोज़र लेता है, जो केवल तभी कॉल किया जाता है जब Option None के बराबर हो। यह संसाधनों को बचाता है:

\n
fn main() {\n    let user_id = 2;\n    let error_msg = format!("User with id {} not found", user_id);\n    let name = get_user_name(user_id).ok_or_else(|| error_msg.clone());\n    // या इससे भी बेहतर:\n    let name = get_user_name(user_id).ok_or_else(|| format!("User {} not found", user_id));\n    println!("{:?}", name);\n}
\n

सुझाव: यदि त्रुटि संदेश एक स्थिरांक है, तो ok_or का उपयोग करें। यदि त्रुटि संदेश की गणना करनी है या यह महँगा है, तो ok_or_else का उपयोग करें।

ब्लॉग

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