A function that might fail can return `Result<T, E>` instead of mixing errors into its normal output. This standard-library enum holds either `Ok(T)`, a successful value, or `Err(E)`, an error value. For example, a FizzBuzz function can return its usual FizzBuzz value for valid input and an error for a negative number. section 2.5.2
The caller must account for both possibilities. A `match` can use the value inside `Ok` or handle `Err`. A function that only prints on success can return `Result<(), Error>`: `()` is the unit type, used when there is no success value to return. section 2.5.2 section 2.6
When a function should pass an error to its caller, `?` shortens a `match` with an early return. On `Ok`, the expression yields the contained value; on `Err`, it returns the error immediately. Error types can also be specific: an `Error::GotNegative` variant gives the caller a case to handle. section 2.5.4
Listing 2.34 Example use of the ? operator
fn foo(i: i32) -> Result<FizzBuzzValue, Error> {
let result = match fizzbuzz(i) { #1
Ok(x) => {
x
}
Err(e) => {
return Err(e);
}
};
println!("{} is a valid number for fizzbuzz", i);
Ok(result);
}
fn bar(i: i32) -> Result<FizzBuzzValue, Error> {
let result = fizzbuzz(i)?; #2
println!("{} is a valid number for fizzbuzz", i); #3
Ok(result);
}
Compare the explicit `match` and the shorter `?` form for forwarding a FizzBuzz error. section 2.5.4
Giving validation failures useful names
Suppose lowercase and uniqueness checks each return `Result<(), ()>`. A username validator needs to distinguish their failures. Applying `map_err` to each result converts its uninformative `Err(())` into `UsernameError::NotLowercase` or `UsernameError::NotUnique`; `?` then forwards the converted error. Successful checks continue to the final `Ok(())`. section 2.5.5
Listing 2.36 Program that validates usernames
enum UsernameError {
NotLowercase,
NotUnique,
}
fn main() {
match validate_username("user1") {
Ok(()) => println!("Valid username"),
Err(UsernameError::NotLowercase) => println!(
"Username must be lowercase"),
Err(UsernameError::NotUnique) => println!(
"Username already exists"),
}
}
fn validate_username(username: &str) -> Result<(), UsernameError>
{
validate_lowercase(username).map_err(
|_| UsernameError::NotLowercase)?;
validate_unique(username).map_err(
|_| UsernameError::NotUnique)?;
Ok(())
}
fn validate_lowercase(username: &str) -> Result<(), ()> {
Ok(()) #1
}
fn validate_unique(username: &str) -> Result<(), ()> {
Ok(())
}
See the complete validator and the caller’s separate handling of its two error variants. section 2.5.5







