fn read_username_from_file() -> Result<String, io::Error> {
let f = File::open("hello.txt");
let mut f = match f {
Ok(file) => file,
Err(e) => return Err(e),
};
let mut s = String::new();
match f.read_to_string(&mut s) {
Ok(_) => Ok(s),
Err(e) => Err(e),
}
}
Rust has a solution to this, the ? operator. It used to be a macro back in the early days, but it basically means: give me the value here if everything's ok, or return the error if not.
So your example becomes:
fn read_username_from_file() -> Result<String, io::Error> {
let f = File::open("hello.txt");
let mut s = String::new();
f?.read_to_string(&mut s)?
Ok(s)
}
The overhead here is similar to exceptions with better enforcement around handling. This is a massive improvement on C-style error return values.
That makes a bit more sense to me. I'm not convinced that its better than Exceptions (though I never really loved Exceptions either).. but you're right that this makes it much better than the old C way. My only problem is that if you forget a little '?' somewhere you don't get proper error handling. Exceptions aren't as brittle.
In C we used to write macros to accomplish such things but of course they are more verbose.
Most of the time if you forget a ? somewhere then your program won't compile, because you'll have an Option/Result, not the value you're expecting in a given expression.
You're correct though that there's a hole where functions return Result<(), Error> because you can ignore the return value without getting an error, however the Rust compiler will spit out a warning for an unused Result:
warning: unused `std::result::Result` that must be used
--> src/lib.rs:9:5
|
9 | f?.read_to_string(&mut s);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: #[warn(unused_must_use)] on by default
= note: this `Result` may be an `Err` variant, which should be handled
So while I agree that Rust isn't head and shoulders better than C++ in every way, I think error handling is currently one area where Rust has a significant advantage.
Rust has a solution to this, the ? operator. It used to be a macro back in the early days, but it basically means: give me the value here if everything's ok, or return the error if not.
So your example becomes:
The overhead here is similar to exceptions with better enforcement around handling. This is a massive improvement on C-style error return values.
Thanks Nick.
That makes a bit more sense to me. I'm not convinced that its better than Exceptions (though I never really loved Exceptions either).. but you're right that this makes it much better than the old C way. My only problem is that if you forget a little '?' somewhere you don't get proper error handling. Exceptions aren't as brittle.
In C we used to write macros to accomplish such things but of course they are more verbose.
Most of the time if you forget a
?
somewhere then your program won't compile, because you'll have anOption
/Result
, not the value you're expecting in a given expression.You're correct though that there's a hole where functions return
Result<(), Error>
because you can ignore the return value without getting an error, however the Rust compiler will spit out a warning for an unusedResult
:So while I agree that Rust isn't head and shoulders better than C++ in every way, I think error handling is currently one area where Rust has a significant advantage.
thanks for the info Nick.