What is this question mark operator about? - rust

I'm reading the documentation for File:
//..
let mut file = File::create("foo.txt")?;
//..
What is the ? in this line? I do not recall seeing it in the Rust Book before.

As you may have noticed, Rust does not have exceptions. It has panics, but their use for error-handling is discouraged (they are meant for unrecoverable errors).
In Rust, error handling uses Result. A typical example would be:
fn halves_if_even(i: i32) -> Result<i32, Error> {
if i % 2 == 0 {
Ok(i / 2)
} else {
Err(/* something */)
}
}
fn do_the_thing(i: i32) -> Result<i32, Error> {
let i = match halves_if_even(i) {
Ok(i) => i,
Err(e) => return Err(e),
};
// use `i`
}
This is great because:
when writing the code you cannot accidentally forget to deal with the error,
when reading the code you can immediately see that there is a potential for error right here.
It's less than ideal, however, in that it is very verbose. This is where the question mark operator ? comes in.
The above can be rewritten as:
fn do_the_thing(i: i32) -> Result<i32, Error> {
let i = halves_if_even(i)?;
// use `i`
}
which is much more concise.
What ? does here is equivalent to the match statement above with an addition. In short:
It unpacks the Result if OK
It returns the error if not, calling From::from on the error value to potentially convert it to another type.
It's a bit magic, but error handling needs some magic to cut down the boilerplate, and unlike exceptions it is immediately visible which function calls may or may not error out: those that are adorned with ?.
One example of the magic is that this also works for Option:
// Assume
// fn halves_if_even(i: i32) -> Option<i32>
fn do_the_thing(i: i32) -> Option<i32> {
let i = halves_if_even(i)?;
// use `i`
}
The ? operator, stabilized in Rust version 1.13.0 is powered by the (unstable) Try trait.
See also:
Is the question mark operator ? equivalent to the try! macro?
Why do try!() and ? not compile when used in a function that doesn't return Option or Result?

It is a postfix operator that unwraps Result<T, E> and Option<T> values.
If applied to Result<T, E>, it unwraps the result and gives you the inner value, propagating the error to the calling function.
let number = "42".parse::<i32>()?;
println!("{:?}", number); // 42
When applied to an Option<T>, it propagates None to the caller, leaving you the content of the Some branch to deal with.
let val = Some(42)?;
println!("{:?}", val); // 42
The ? operator can only be used in a function that returns Result or Option like so:
use std::num::ParseIntError;
fn main() -> Result<(), ParseIntError> {
let number = "42".parse::<i32>()?;
println!("{:?}", number);
Ok(())
}
It is a convenience offered by Rust, that eliminates boilerplate code and makes function's implementation simpler.

It is used for propagating errors. Sometimes we write code that might fail but we do not want to catch and handle error immediately. Your code will not be readable if you have too much code to handle the error in every place. Instead, if an error occurs, we might want to let our caller deal with it. We want errors to propagate up the call stack.
// file type is Result if "?" is not used
// file:Result<File,Error>
let mut file = File::create("foo.txt");
// file type is File if "?" is used
// file:File
let mut file = File::create("foo.txt")?;
// if an error occurs, code after this line will not be executed
// function will return the error
The behavior of ? depends on whether this function returns a successful result or an error result:
If it is a success, it unwraps the Result to get the success value inside. Value is assigned to the variable file
If the result is an error, the error is NOT assigned to the variable file. Error is returned by the function to the caller
Using ? same as this code
let mut file = match File::create("foo.txt") {
Err(why) => panic!("couldn't create {}: {}", display, why),
Ok(file) => file,
};
? also works similarly with the Option type. In a function that returns Option, you
can use ? to unwrap a value and return early in the case of None :

The existing answers are all great! I would like to give a small code snippet to demo the use of From::from() behand this question mark:
fn _parse(str: &str) -> Result<i32, &str> {
if let Ok(num) = str.parse::<i32>() {
Ok(num)
} else {
Err(str)
}
}
fn parse(str: &str) -> Result<(), String> {
let num = _parse(str)?;
println!("{}", num);
Ok(())
}
The use of ? in function parse() can be manually rewritten as:
fn parse(str: &str) -> Result<(), String> {
match _parse(str) {
Ok(n) => {
println!("{}", n);
Ok(())
}
Err(str) => Err(<String as From<&str>>::from(str)),
}
}

Related

Is there a Rust Result method like expect but which propagates the error instead of panicking?

You can unwrap a Result (panic on Err) with a custom message using expect.
How can you propagate an error with a custom message (rather than the default message with ?)?
use std::io::{Result, Error, ErrorKind};
fn main() -> Result<()> {
let a = Err(Error::new(ErrorKind::other, "default message"));
// Let's pretend a is a result automatically created by some other method.
let b = a.unwrap(); // panics with default message
let b = a.expect("custom message"); // panics with custom message
let b = a?; // Returns Err with default message
let b = /* What goes here? */ // Returns Err with custom message
}
There's a few ways to handle this. First, recognize that there is no standard "custom error message" in this context, because in Result<T, E>, the E type can be any type at all, even one that doesn't implement std::error::Error. So, the analogy to the panicking methods doesn't exactly hold. In particular, note that a? does not return "Err with default message!" (See below for an explanation.) What you might be looking for instead is a mechanism to convert from one error type to another.
One way to do this is with Result::map_err, which maps one error value to another.
struct ErrorA;
struct ErrorB;
fn foo() -> Result<(), ErrorA> { todo!() }
fn example() -> Result<(), ErrorB> {
let a = foo();
let b = a.map_err(|_| ErrorB);
b
}
However, you can make this automatic by realizing that ? operator performs Into-based conversion of the error. The expression a? is roughly equivalent to:
match a {
Ok(v) => v,
Err(e) => return Err(std::convert::Into::into(e)),
}
This means it will automatically convert between error types if a suitable Into impl exists. For example:
struct ErrorA;
struct ErrorB;
impl From<ErrorA> for ErrorB {
fn from(_: ErrorA) -> Self { Self }
}
fn foo() -> Result<(), ErrorA> { todo!() }
fn example() -> Result<(), ErrorB> {
let a = foo();
let b = a?; // Conversion to ErrorB is implicit
Ok(b)
}
If you really want just a "custom string" error then you can use String or &'static str as the error type. This can be problematic in some contexts though, because neither of these types implement std::error::Error. However, there is a conversion from both to Box<dyn Error>, so if you don't want to define your own error type you can do something like:
struct ErrorA;
fn foo() -> Result<(), ErrorA> { todo!() }
fn example() -> Result<(), Box<dyn std::error::Error>> {
let a = foo();
// ? converts the &str to Box<dyn Error>
let b = a.map_err(|_| "custom error message")?;
Ok(b)
}
This approach is suitable for simple Rust programs, but generally shouldn't be used in Rust libraries. Custom error types are more suitable for libraries as they allow callers to distinguish different failure scenarios.
Further reading:
The Rust Programming Language - Recoverable Errors with Result

What is the difference between the ? operator and returning Err(e)? [duplicate]

I'm reading the documentation for File:
//..
let mut file = File::create("foo.txt")?;
//..
What is the ? in this line? I do not recall seeing it in the Rust Book before.
As you may have noticed, Rust does not have exceptions. It has panics, but their use for error-handling is discouraged (they are meant for unrecoverable errors).
In Rust, error handling uses Result. A typical example would be:
fn halves_if_even(i: i32) -> Result<i32, Error> {
if i % 2 == 0 {
Ok(i / 2)
} else {
Err(/* something */)
}
}
fn do_the_thing(i: i32) -> Result<i32, Error> {
let i = match halves_if_even(i) {
Ok(i) => i,
Err(e) => return Err(e),
};
// use `i`
}
This is great because:
when writing the code you cannot accidentally forget to deal with the error,
when reading the code you can immediately see that there is a potential for error right here.
It's less than ideal, however, in that it is very verbose. This is where the question mark operator ? comes in.
The above can be rewritten as:
fn do_the_thing(i: i32) -> Result<i32, Error> {
let i = halves_if_even(i)?;
// use `i`
}
which is much more concise.
What ? does here is equivalent to the match statement above with an addition. In short:
It unpacks the Result if OK
It returns the error if not, calling From::from on the error value to potentially convert it to another type.
It's a bit magic, but error handling needs some magic to cut down the boilerplate, and unlike exceptions it is immediately visible which function calls may or may not error out: those that are adorned with ?.
One example of the magic is that this also works for Option:
// Assume
// fn halves_if_even(i: i32) -> Option<i32>
fn do_the_thing(i: i32) -> Option<i32> {
let i = halves_if_even(i)?;
// use `i`
}
The ? operator, stabilized in Rust version 1.13.0 is powered by the (unstable) Try trait.
See also:
Is the question mark operator ? equivalent to the try! macro?
Why do try!() and ? not compile when used in a function that doesn't return Option or Result?
It is a postfix operator that unwraps Result<T, E> and Option<T> values.
If applied to Result<T, E>, it unwraps the result and gives you the inner value, propagating the error to the calling function.
let number = "42".parse::<i32>()?;
println!("{:?}", number); // 42
When applied to an Option<T>, it propagates None to the caller, leaving you the content of the Some branch to deal with.
let val = Some(42)?;
println!("{:?}", val); // 42
The ? operator can only be used in a function that returns Result or Option like so:
use std::num::ParseIntError;
fn main() -> Result<(), ParseIntError> {
let number = "42".parse::<i32>()?;
println!("{:?}", number);
Ok(())
}
It is a convenience offered by Rust, that eliminates boilerplate code and makes function's implementation simpler.
It is used for propagating errors. Sometimes we write code that might fail but we do not want to catch and handle error immediately. Your code will not be readable if you have too much code to handle the error in every place. Instead, if an error occurs, we might want to let our caller deal with it. We want errors to propagate up the call stack.
// file type is Result if "?" is not used
// file:Result<File,Error>
let mut file = File::create("foo.txt");
// file type is File if "?" is used
// file:File
let mut file = File::create("foo.txt")?;
// if an error occurs, code after this line will not be executed
// function will return the error
The behavior of ? depends on whether this function returns a successful result or an error result:
If it is a success, it unwraps the Result to get the success value inside. Value is assigned to the variable file
If the result is an error, the error is NOT assigned to the variable file. Error is returned by the function to the caller
Using ? same as this code
let mut file = match File::create("foo.txt") {
Err(why) => panic!("couldn't create {}: {}", display, why),
Ok(file) => file,
};
? also works similarly with the Option type. In a function that returns Option, you
can use ? to unwrap a value and return early in the case of None :
The existing answers are all great! I would like to give a small code snippet to demo the use of From::from() behand this question mark:
fn _parse(str: &str) -> Result<i32, &str> {
if let Ok(num) = str.parse::<i32>() {
Ok(num)
} else {
Err(str)
}
}
fn parse(str: &str) -> Result<(), String> {
let num = _parse(str)?;
println!("{}", num);
Ok(())
}
The use of ? in function parse() can be manually rewritten as:
fn parse(str: &str) -> Result<(), String> {
match _parse(str) {
Ok(n) => {
println!("{}", n);
Ok(())
}
Err(str) => Err(<String as From<&str>>::from(str)),
}
}

What is the difference between `then`, `and_then` and `or_else` in Rust futures?

I am learning to use Rust futures and I am finding it extremely confusing. I feel like I am being stupid but when would then, and_then and or_else be used? What return types are expected?
Please provide some examples of the different situations you would expect to see them.
TL;DR: then is used when you want to do something regardless of if the future was successful or not, and_then runs the closure only when the future succeeded, and or_else runs the closure only when the future failed.
and_then and or_else are direct analogs to the methods of the same name on Result .
Your first step should be to read the docs. The documentation contains the exact method signatures (which explain what types it expects and what the return types are), prose describing each method, and example usage as well.
I've extracted small snippets of the docs and emphasized the relevant parts.
Future::then:
This function can be used to ensure a computation runs regardless of
the conclusion of the future. The closure provided will be yielded a
Result once the future is complete.
The returned value of the closure must implement the IntoFuture trait
and can represent some more work to be done before the composed future
is finished.
Future::and_then:
This function can be used to chain two futures together and ensure
that the final future isn't resolved until both have finished. The
closure provided is yielded the successful result of this future and
returns another value which can be converted into a future.
Future::or_else
Return a future that passes along this future's value if it succeeds, and otherwise passes the error to the closure f and waits for the future it returns.
The return type for all three methods is any type that can be converted into another future.
then: no additional restrictions on the return type.
and_then requires that the error type of the returned future match the starting future's error type.
or_else requires that the success type of the returned future match the starting future's success type.
use futures::{future, Future}; // 0.1.25
struct Error;
fn download_from_server(server: u8) -> impl Future<Item = Vec<u8>, Error = Error> {
/* ... */
}
fn upload_to_server(data: Vec<u8>) -> impl Future<Item = usize, Error = Error> {
/* ... */
}
// Uses `or_else` to do work on failure
fn download() -> impl Future<Item = Vec<u8>, Error = Error> {
download_from_server(0)
.or_else(|_| download_from_server(1))
.or_else(|_| download_from_server(2))
}
// Uses `and_then` to do work on success
fn reupload() -> impl Future<Item = usize, Error = Error> {
download().and_then(|data| upload_to_server(data))
}
// Uses `then` to always do work
fn do_things() -> impl Future<Item = (), Error = ()> {
reupload().then(|r| {
match r {
Ok(size) => println!("Uploaded {} bytes", size),
Err(_) => println!("Got an error"),
};
Ok(())
})
}
Some cases are simplified by the async / await syntax stabilized in Rust 1.39:
// Equivalent to `or_else`
async fn download() -> Result<Vec<u8>, Error> {
match download_from_server(0).await {
Ok(v) => Ok(v),
Err(_) => match download_from_server(1).await {
Ok(v) => Ok(v),
Err(_) => download_from_server(2).await,
},
}
}
// Equivalent to `and_then`
async fn reupload() -> Result<usize, Error> {
let data = download().await?;
upload_to_server(data).await
}
// Equivalent to `then`
async fn do_things() -> Result<(), ()> {
match reupload().await {
Ok(size) => println!("Uploaded {} bytes", size),
Err(_) => println!("Got an error"),
}
Ok(())
}

What's the recommended way to produce side effects in control flow using Result?

Result::and_then() works great for composing control flow.
fn some_fn() -> Result<String, Error> {
Ok("Yay".to_string())
}
some_fn()
.and_then(|value| some_other_fn())
.and_then(|some_other_value| /* ... */)
Sometimes we want to create a side effect and still propagate the emitted value. Let's say we want to print the value the moment we receive it:
some_fn()
.and_then(|value| {
println!("{}", &value);
some_other_fn()
})
.and_then(|some_other_value| /* ... */)
Is there a better way to do this? Something like Reactive Extensions' tap() operator would be great.
map and and_then are appropriate for when you want to transform the value. Using match or if let is appropriate for side effects:
let r = some_fn();
if let Ok(v) = &r {
println!("{}", v);
}
r.and_then(|_| some_other_fn())
See also:
Why does Rust need the `if let` syntax?
Assuming that you only care about side effects when the Result is Ok...
You could also create an extension trait to add the desired method to Result. I'd advocate for calling it inspect as that's the name of the parallel method on Iterator.
trait InspectExt<T> {
fn inspect<F>(self, f: F) -> Self
where
F: FnOnce(&T);
}
impl<T, E> InspectExt<T> for Result<T, E> {
fn inspect<F>(self, f: F) -> Self
where
F: FnOnce(&T),
{
if let Ok(v) = &self {
f(v)
}
self
}
}
some_fn()
.inspect(|v| println!("{}", v))
.and_then(|_| some_fn())
See also:
Is there a way other than traits to add methods to a type I don't own?

What is unwrap in Rust, and what is it used for?

I have this code that uses .unwrap():
fn main() {
let paths = std::fs::read_dir("/home/user").unwrap();
for path in paths {
println!("Name: {}", path.unwrap().path().display());
}
}
After looking at the definition of unwrap,
pub fn unwrap(self) -> T {
match self {
Ok(t) => t,
Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", e),
}
}
And the signature of read_dir
pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir>
Am I correct in understanding that unwrap returns the T type that is passed in Result?
In Rust, when you have an operation that may either return a T or fail, you will have a value of type Result<T,E> or Option<T> (E will be the error condition in case of an interesting error).
The function unwrap(self) -> T will give you the embedded T if there is one. If instead there is not a T but an E or None then it will panic.
It is best used when you are positively sure that you don't have an error. If that is not the case usually it is better either pattern-match the error or use the try! macro ? operator to forward the error.
In your example, the call to read_dir() returns a io::Result<ReadDir> because opening the directory might fail. And iterating the opened directory returns multiple values of type io::Result<DirEntry> because reading the directory might also fail.
With try! ? it would be something like this:
fn try_main() -> std::io::Result<()> {
let entries = std::fs::read_dir("/home/user")?;
for entry in entries {
println!("Name: {}", entry?.path().display());
}
Ok(())
}
fn main() {
let res = try_main();
if let Err(e) = res {
println!("Error: {}", e);
}
}
Look how every error case is checked.
(Updated to use ? instead of try!(). The macro still works, but the ? is preferred for new code).
The problem is that reading a line from a file produces a potential error type. The type is
Result<String,std::io::Error>
Result is an enum. There are two potential values in the Result, they are used for error handling and management. The first value is Err. If Err is populated, there was an error in the function that was called. The other potential selection is Ok. Ok contains a value.
enum Result<T, E> {
Ok(T),
Err(E),
}
Enum is a complex type, rather than a single value. To get the value we are looking for, we use unwrap() to unwrap the value.
unwrap() is used here to handle the errors quickly. It can be used on any function that returns Result or Option (Option is also enum). If the function returns an Ok(value), you will get the value. If the function returns an Err(error), the program will panic.

Resources