Rust में त्रुटि प्रबंधन: try/catch और उससे आगे — उन्नत स्तर
\n\nकई भाषाओं के विपरीत, जहाँ अपवाद (exceptions) एक मानक तंत्र हैं (जैसे Python, Java या C++ में try/catch), Rust एक मौलिक रूप से भिन्न दृष्टिकोण प्रस्तुत करता है। यहाँ शास्त्रीय अर्थों में कोई अपवाद नहीं हैं। इसके बजाय, भाषा त्रुटियों को प्रस्तुत करने और संसाधित करने के लिए एक शक्तिशाली प्रकार प्रणाली (type system) का उपयोग करती है। एक शुरुआत करने वाले के लिए यह जटिल लग सकता है, लेकिन उन्नत स्तर पर, आप उस सुरक्षा और पूर्वानुमेयता की सराहना करेंगे जो यह दृष्टिकोण प्रदान करता है। इस लेख में, हम Rust में पेशेवर रूप से त्रुटियों के साथ काम करने का तरीका समझेंगे: बुनियादी Result और Option से लेकर उन्नत क्रेट्स anyhow और thiserror तक, और परिचित try/catch के साथ समानताएँ भी बनाएँगे।
1. आधार: Result, Option और ? ऑपरेटर
\n\nRust में त्रुटि प्रबंधन का आधार Result<T, E> एनुमरेशन है। यह या तो Ok(T) (सफलता) या Err(E) (त्रुटि) हो सकता है। try/catch का एनालॉग ? ऑपरेटर माना जा सकता है। यह त्रुटि को ऊपर भेजने (propagate) को सरल बनाता है: यदि मान Err है, तो फ़ंक्शन तुरंत इसे लौटाता है; यदि Ok है, तो मान निकालता है।
use std::fs::File;\nuse std::io::Read;\n\nfn read_file(path: &str) -> Result<String, std::io::Error> {\n let mut file = File::open(path)?; // try का एनालॉग: त्रुटि को आगे भेजना\n let mut content = String::new();\n file.read_to_string(&mut content)?;\n Ok(content)\n}\n\nइस उदाहरण में, File::open और read_to_string Err लौटा सकते हैं। ? ऑपरेटर भारी-भरकम match को बदल देता है और कोड को अन्य भाषाओं में try/catch की तरह साफ बनाता है। हालाँकि, अपवादों के विपरीत, आप फ़ंक्शन के सिग्नेचर में त्रुटि के प्रकार को स्पष्ट रूप से निर्दिष्ट करते हैं — इससे पठनीयता और सुरक्षा बढ़ती है।
Option<T> एनुमरेशन का उपयोग उन मामलों के लिए किया जाता है जहाँ मान अनुपस्थित हो सकता है (Python में None का एनालॉग)। ? ऑपरेटर इसके साथ भी काम करता है:
fn get_first_element(vec: &Vec<i32>) -> Option<&i32> {\n vec.first()? // यदि वेक्टर खाली है, तो None लौटाएँ\n}\n\n2. त्रुटि प्रकारों के साथ उन्नत कार्य: From और Error ट्रेट्स
\n\nजब कोई फ़ंक्शन विभिन्न त्रुटि प्रकारों (जैसे, इनपुट-आउटपुट और पार्सिंग) के साथ कई ऑपरेशन कॉल करता है, तो एक समस्या उत्पन्न होती है: एक एकीकृत प्रकार कैसे लौटाया जाए? समाधान From ट्रेट और एक कस्टम त्रुटि प्रकार है।
आइए अपनी स्वयं की त्रुटि संरचना बनाएँ और इसके लिए std::error::Error ट्रेट को लागू करें (स्वचालित रूप से #[derive(Debug)] के माध्यम से और Display के मैन्युअल कार्यान्वयन के साथ):
use std::fmt;\nuse std::io;\n\n#[derive(Debug)]\nenum MyError {\n Io(io::Error),\n Parse(std::num::ParseIntError),\n}\n\nimpl fmt::Display for MyError {\n fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n match self {\n MyError::Io(e) => write!(f, "IO error: {}", e),\n MyError::Parse(e) => write!(f, "Parse error: {}", e),\n }\n }\n}\n\nimpl std::error::Error for MyError {}\n\n// स्वचालित रूपांतरण के लिए From लागू करें\nimpl From<io::Error> for MyError {\n fn from(error: io::Error) -> Self {\n MyError::Io(error)\n }\n}\n\nimpl From<std::num::ParseIntError> for MyError {\n fn from(error: std::num::ParseIntError) -> Self {\n MyError::Parse(error)\n }\n}\n\nfn process_data(path: &str) -> Result<i32, MyError> {\n let content = std::fs::read_to_string(path)?; // स्वचालित रूप से MyError::Io में परिवर्तित होता है\n let number: i32 = content.trim().parse()?; // स्वचालित रूप से MyError::Parse में परिवर्तित होता है\n Ok(number)\n}\n\nअब फ़ंक्शन process_data एक एकीकृत प्रकार MyError लौटाता है, और ? ऑपरेटर लागू किए गए ट्रेट के कारण स्वचालित रूप से त्रुटियों को परिवर्तित करता है