Errors
Using the ?
operator propagates the error from the expression. How this works depends on whether ?
is used from an async expression or from a handler. Using ?
in an async expression propagates the error out of the async expression. This makes the output of the async expression a Result
. Using ?
from a handler immediately propagates the error out of the select!
expression. Let’s look at the accept loop example again:
use tokio::net::TcpListener;
use tokio::sync::oneshot;
use std::io;
#[tokio::main]
async fn main() -> io::Result<()> {
// [setup `rx` oneshot channel]
let listener = TcpListener::bind("localhost:3465").await?;
tokio::select! {
res = async {
loop {
let (socket, _) = listener.accept().await?;
tokio::spawn(async move { process(socket) });
}
// Help the rust type inferencer out
Ok::<_, io::Error>(())
} => {
res?;
}
_ = rx => {
println!("terminating accept loop");
}
}
Ok(())
}
Notice listener.accept().await?
. The ?
operator propagates the error out of that expression and to the res
binding. On an error, res
will be set to Err(_)
. Then, in the handler, the ?
operator is used again. The res?
statement will propagate an error out of the main
function.