Early returns and the ? operator

This is another pattern that is quite common when we interact with Result types. The pattern goes as follows: when we have a success value, we immediately want to extract it, but when we have an error value, we want to make an early return and propagate the error to the caller. To illustrate this pattern, we will use the following snippet, which uses the usual match expression to act on the Result type:

// result_common_pattern.rs

use std::string::FromUtf8Error;

fn str_upper_match(str: Vec<u8>) -> Result<String, FromUtf8Error> {
let ret = match String::from_utf8(str) {
Ok(str) => str.to_uppercase(),
Err(err) => return Err(err)
};

println!("Conversion succeeded: {}", ret);
Ok(ret)
}

fn main() {
let invalid_str = str_upper_match(vec![197, 198]);
println!("{:?}", invalid_str);
}

The ? operator abstracts this pattern, making it possible to write the bytes_to_str method in a more concise way:

// using_question_operator.rs

use std::string::FromUtf8Error;

fn str_upper_concise(str: Vec<u8>) -> Result<String, FromUtf8Error> {
let ret = String::from_utf8(str).map(|s| s.to_uppercase())?;
println!("Conversion succeeded: {}", ret);
Ok(ret)
}

fn main() {
let valid_str = str_upper_concise(vec![121, 97, 89]);
println!("{:?}", valid_str);
}

This operator becomes even nicer if you have a sequence of Result/Option returning method calls, where a failure in each operator should mean a failure of the whole. For instance, we could write the whole operation of creating a file and writing to it as follows:

let _ = File::create("foo.txt")?.write_all(b"Hello world!")?;

It works pretty much as a replacement for the try! macro, which does the same thing as before ? was implemented in the compiler. Now, ? is a replacement for that, but there are some plans to make it more generic and usable for other cases, too.

Bonus tip: The main function also allows you to return Result types. Specifically, it allows you to return types that implement the Termination trait. This means that we can also write main as follows:

// main_result.rs

fn main() -> Result<(), &'static str> {
let s = vec!["apple", "mango", "banana"];
let fourth = s.get(4).ok_or("I got only 3 fruits")?;
Ok(())
}

Next, let's move on to dealing with non-recoverable errors.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset