Use and_then to chain operations that return Result values, ensuring the next step only executes if the previous one succeeded. It acts as a monadic bind, automatically propagating Err values without explicit if let or match blocks.
Here is a practical example showing how to parse a string, convert it to an integer, and then double it, failing gracefully at any step:
fn parse_and_double(s: &str) -> Result<i32, String> {
s.parse::<i32>()
.map_err(|_| "Invalid number".to_string())
.and_then(|n| {
// This closure only runs if parse succeeded
if n > 100 {
Err("Number too large".to_string())
} else {
Ok(n * 2)
}
})
}
fn main() {
println!("{:?}", parse_and_double("42")); // Ok(84)
println!("{:?}", parse_and_double("abc")); // Err("Invalid number")
println!("{:?}", parse_and_double("200")); // Err("Number too large")
}
While and_then is the explicit method for this pattern, you will often see the ? operator used instead in modern Rust code. The ? operator is syntactic sugar that performs the same logic: it returns the Err immediately if the value is an error, or unwraps the Ok value to continue the chain.
For example, the logic above is more commonly written as:
fn parse_and_double(s: &str) -> Result<i32, String> {
let n = s.parse::<i32>()?;
if n > 100 {
return Err("Number too large".to_string());
}
Ok(n * 2)
}
Use and_then specifically when you need to define the next step as a closure, such as when you need to capture variables from the outer scope that aren't available in a linear function body, or when composing functions dynamically. In standard linear function bodies, prefer ? for readability.