thiserror
- Rust course
- Intermediate
- Lesson 66/115
- 4 min
Build derived error types with the thiserror crate.
thiserror
In libraries, error types are usually an enum, and writing Display for each variant is repetitive. The thiserror crate generates it with a derive:
// Cargo.toml: thiserror = "1"
use thiserror::Error;
#[derive(Debug, Error)]
enum AyarHatasi {
#[error("eksik anahtar: {0}")]
Eksik(String),
#[error("geçersiz değer: {anahtar}={deger}")]
Gecersiz { anahtar: String, deger: String },
}The code it generates is identical to the impl Display and impl Error you would write by hand; there's no runtime cost.
The hand-written equivalent
Since there are no external crates in the exercise environment, we'll write the same type by hand. This is what's behind thiserror:
impl fmt::Display for AyarHatasi {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AyarHatasi::Eksik(a) => write!(f, "eksik anahtar: {a}"),
AyarHatasi::Gecersiz { anahtar, deger } => {
write!(f, "geçersiz değer: {anahtar}={deger}")
}
}
}
}
impl std::error::Error for AyarHatasi {}Practice Settings errors
Define the AyarHatasi enum with the variants Eksik(String) and Gecersiz { anahtar, deger }; implement Display and Error by hand. Print Eksik("port") and Gecersiz { anahtar: "port", deger: "abc" } with {} on separate lines.
Starter code
use std::fmt;
fn main() {
// buraya yaz
}Sample solution
use std::fmt;
#[derive(Debug)]
enum AyarHatasi {
Eksik(String),
Gecersiz { anahtar: String, deger: String },
}
impl fmt::Display for AyarHatasi {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AyarHatasi::Eksik(a) => write!(f, "eksik anahtar: {a}"),
AyarHatasi::Gecersiz { anahtar, deger } => {
write!(f, "geçersiz değer: {anahtar}={deger}")
}
}
}
}
impl std::error::Error for AyarHatasi {}
fn main() {
let a = AyarHatasi::Eksik(String::from("port"));
let b = AyarHatasi::Gecersiz {
anahtar: String::from("port"),
deger: String::from("abc"),
};
println!("{}", a);
println!("{}", b);
}Expected output
eksik anahtar: port geçersiz değer: port=abc
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 <code>thiserror</code> or <code>anyhow</code>? What is the general rule?
- thiserror everywhere
- Both do the same thing
- thiserror in libraries (concrete types), anyhow in applications (one flexible type) Correct answer
- anyhow everywhere
Explanation: A library user wants to handle errors by kind; an application mostly reports the error.
2 Message attribute
#[derive(Debug, Error)]
enum AyarHatasi {
#[____("eksik anahtar: {0}")]
Eksik(String),
}
#[derive(Debug, Error)]
enum AyarHatasi {
#[error("eksik anahtar: {0}")]
Eksik(String),
}
Explanation: thiserror takes each variant's message from #[error(..)].
3 Value and message
| Term | Meaning |
|---|---|
Eksik("port") |
eksik anahtar: port |
Gecersiz { port, abc } |
geçersiz değer: port=abc |
#[error("{0}")] |
First field |
#[error(transparent)] |
Inner error's message |