Adding context
- Rust course
- Intermediate
- Lesson 69/115
- 4 min
Add context to errors with anyhow::Context.
Adding context
The message "invalid digit found in string" doesn't say what failed. A good error explains what was being done when it failed. In anyhow there are context and with_context for this:
use anyhow::{Context, Result};
fn port_oku(s: &str) -> Result<u16> {
s.parse::<u16>()
.with_context(|| format!("port okunamadı ({s})"))
}
// error: port okunamadı (99999)
// Caused by: number too large to fit in target typeSince with_context takes a closure, the message is produced only in the error case.
Context with std
Without an external crate, the same effect is achieved with map_err: you combine the lower error and the context into one message:
fn port_oku(s: &str) -> Result<u16, String> {
s.parse::<u16>()
.map_err(|e| format!("port okunamadı ({s}): {e}"))
}
println!("{:?}", port_oku("8080")); // Ok(8080)This turns the lower error into text; to keep the chain, we'll look at the source() method in the next lesson.
Practice Error with context
Write the port_oku function above with map_err. Print the result for "8080" with {:?} and the error for "99999" as plain text, on separate lines.
Starter code
fn main() {
// buraya yaz
}Sample solution
fn port_oku(s: &str) -> Result<u16, String> {
s.parse::<u16>()
.map_err(|e| format!("port okunamadı ({s}): {e}"))
}
fn main() {
println!("{:?}", port_oku("8080"));
if let Err(e) = port_oku("99999") {
println!("{}", e);
}
}Expected output
Ok(8080) port okunamadı (99999): number too large to fit in target type
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 What should a context message mostly include?
- The line number
- The user's name
- Nothing; the lower error is enough
- The operation and the relevant input (file name, key, value) Correct answer
Explanation: The user should be able to find the problem from the message: "ayar.toml okunamadı" makes sense together with "No such file".
2 Lazy context
s.parse::<u16>()
.____(|| format!("port okunamadı ({s})"))
s.parse::<u16>()
.with_context(|| format!("port okunamadı ({s})"))
Explanation: with_context produces the message only when there's an error.
3 Input and port_oku result
| Term | Meaning |
|---|---|
"8080" |
Ok(8080) |
"99999" |
number too large ... |
"abc" |
invalid digit ... |
"" |
cannot parse ... empty string |