? operator
- Rust course
- Beginner
- Lesson 108/115
- 4 min
Propagate errors automatically to the caller with ?.
The ? operator
? unpacks a Result: if it's Ok(v) it gives v, if it's Err(e) it immediately returns Err(e) from the function. It reduces error-propagation code to one character:
use std::num::ParseIntError;
fn topla(a: &str, b: &str) -> Result<i32, ParseIntError> {
let x: i32 = a.parse()?;
let y: i32 = b.parse()?;
Ok(x + y)
}? can only be used in functions that return Result (or Option).
? and From
Before returning the error, ? converts it to the function's error type with From::from. This way different error types can be gathered into one type:
use std::error::Error;
fn oku(s: &str) -> Result<f64, Box<dyn Error>> {
let n: i32 = s.parse()?; // ParseIntError → Box<dyn Error>
let k: f64 = "2.5".parse()?; // ParseFloatError → Box<dyn Error>
Ok(n as f64 * k)
}In a function returning Option, ? propagates None upward.
Practice Add texts
Write the function fn topla(a: &str, b: &str) -> Result<i32, ParseIntError> above with ?. Print the results of topla("2", "3") and topla("2", "x") with {:?}, separated by a space.
Starter code
use std::num::ParseIntError;
fn main() {
// buraya yaz
}Sample solution
use std::num::ParseIntError;
fn topla(a: &str, b: &str) -> Result<i32, ParseIntError> {
let x: i32 = a.parse()?;
let y: i32 = b.parse()?;
Ok(x + y)
}
fn main() {
println!("{:?} {:?}", topla("2", "3"), topla("2", "x"));
}Expected output
Ok(5) Err(ParseIntError { kind: InvalidDigit })
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 Why doesn't <code>fn main() { let n: i32 = "5".parse()?; }</code> compile?
- "5" is invalid
- It compiles
- main returns (); ? needs it to return a Result Correct answer
- parse is misused
Explanation: main can return a Result too: fn main() -> Result<(), Box<dyn std::error::Error>> { ...; Ok(()) }.
2 Propagate the error
fn sayi(s: &str) -> Result<i32, std::num::ParseIntError> {
let n: i32 = s.parse()____;
Ok(n * 2)
}
fn sayi(s: &str) -> Result<i32, std::num::ParseIntError> {
let n: i32 = s.parse()?;
Ok(n * 2)
}
Explanation: ? returns the Err to the caller immediately on failure.
3 Syntax and meaning
| Term | Meaning |
|---|---|
x? |
Unpack Ok, return on Err |
Box<dyn Error> |
Any error type |
From::from |
Error conversion |
opt? |
Propagates None |