Error Propagation के Patterns
In this page:
fn name() -> Result<T, Box<dyn Error>> {
let value = step()?;
Ok(value)
}
impl From<Source> for NameError {
fn from(e: Source) -> Self { NameError::Variant(e) }
}
Propagating with ? Across Functions
एक helper function ? के साथ एक error propagate कर सकता है, इसके caller (या caller के caller) को आखिरकार यह decide करने देते हुए कि कैसे react करना है, बजाय वह decision बहुत जल्दी लेने के।
उदाहरण: Propagating with ? Across Functions
// Define the function `parse_positive` taking `s` and returning a `Result<i32, String>`
fn parse_positive(s: &str) -> Result<i32, String> {
// Declare an immutable variable `n` (an integer), set to `s.parse().map_err(|_| String::from("not a number"))?`
let n: i32 = s.parse().map_err(|_| String::from("not a number"))?;
// Check whether `n < 0`
if n < 0 {
// Return `Err(String::from("must be positive"))` from this function
return Err(String::from("must be positive"));
}
Ok(n)
}
// Entry point: execution of the program starts here
fn main() {
// Print "{:?}" to the console, substituting in `parse_positive("5")` (with a trailing newline)
println!("{:?}", parse_positive("5"));
// Print "{:?}" to the console, substituting in `parse_positive("-3")` (with a trailing newline)
println!("{:?}", parse_positive("-3"));
}
Login to try C/C++/Java/PHP code in the editor
Using Box<dyn Error> for Multiple Error Types
जब कोई function कई unrelated तरीकों से fail हो सकता है (जैसे parsing errors और custom validation errors), Box<dyn std::error::Error> return करना इसे एक flexible return type के तहत unify करने देता है।
उदाहरण: Using Box<dyn Error> for Multiple Error Types
// Bring `std::error::Error` into scope
use std::error::Error;
// Define the function `parse_and_check` taking `s` and returning a `Result<i32, Box<dyn Error>>`
fn parse_and_check(s: &str) -> Result<i32, Box<dyn Error>> {
// Declare an immutable variable `n` (an integer), set to `s.parse()?`
let n: i32 = s.parse()?;
Ok(n * 2)
}
// Define the function `main` with no parameters and returning a `Result<(), Box<dyn Error>>`
fn main() -> Result<(), Box<dyn Error>> {
// Declare an immutable variable `value`, set to `parse_and_check("21")?`
let value = parse_and_check("21")?;
// Print "Value: {}" to the console, substituting in `value` (with a trailing newline)
println!("Value: {}", value);
Ok(())
}
Login to try C/C++/Java/PHP code in the editor
Adding Context While Propagating
एक middle-layer function एक error catch कर सकता है, map_err उपयोग करके इसे ज़्यादा context से wrap कर सकता है, और फिर enriched error को आगे ऊपर propagate कर सकता है, callers को क्या हुआ इसकी clearer picture देते हुए।
उदाहरण: Adding Context While Propagating
// Define the function `load_setting` taking `raw` and returning a `Result<i32, String>`
fn load_setting(raw: &str) -> Result<i32, String> {
raw.parse::<i32>().map_err(|e| format!("failed to load setting: {}", e))
}
// Entry point: execution of the program starts here
fn main() {
// Match on `load_setting("abc")` and branch by pattern
match load_setting("abc") {
Ok(v) => println!("Setting: {}", v),
Err(e) => println!("{}", e),
}
}
Login to try C/C++/Java/PHP code in the editor
main Returning a Result
Rust का main function खुद एक Result return कर सकता है, top-level program को ? सीधे उपयोग करने देते हुए और अगर कुछ fail हो तो अपने आप एक साफ़ error message print करते हुए।
उदाहरण: main Returning a Result
// Define the function `main` with no parameters and returning a `Result<(), std::num::ParseIntError>`
fn main() -> Result<(), std::num::ParseIntError> {
// Declare an immutable variable `value` (an integer), set to `"99".parse()?`
let value: i32 = "99".parse()?;
// Print "Parsed: {}" to the console, substituting in `value` (with a trailing newline)
println!("Parsed: {}", value);
Ok(())
}
Login to try C/C++/Java/PHP code in the editor
- किसी low-level helper function के अंदर हर possible error को handle करना बजाय इसे किसी caller तक bubble up करने देने के जिसके पास ज़्यादा context हो।
- यह भूल जाना कि
Box<dyn Error>एक आम flexible return type है जब कोई function कई अलग-अलग unrelated error types produce कर सकता है। - किसी call chain में गहराई में
?से error को ऊपर propagate करने के बजाय.unwrap()overuse करना, जो पूरे program को crash करता है बजाय किसी caller को decide करने देने के।
?से errors को ऊपर propagate करना higher-level code को यह decide करने देता है कि failures को कैसे handle या report करना है।Box<dyn std::error::Error>उन functions के लिए एक आम return type है जो एक से ज़्यादा distinct तरीके से fail हो सकते हैं।- Layered functions हर एक error को आगे call stack में ऊपर propagate करने से पहले अपना context जोड़ सकते हैं।
- अच्छी error propagation low-level functions को simple रखती है जबकि decision-making को higher levels पर concentrate करती है।
Chapter Quiz — Complete all 6 topics to unlock
0/6 topics done
Complete these topics first: