Tuesday, January 5, 2021

Downcasting boxed errors in Rust

Today I was trying to write polymorphic error handling in Rust, something achievable with dynamic_cast in C++, and incredibly easy in Go. In Rust, of course, it’s overcomplicated.

After a couple frustrating hours of searching with no success, I stumbled upon the downcast_ref method of the Error trait, which finally allowed me to write what I wanted. Oddly enough, I couldn’t find this solution anywhere.

use std::error::Error;
#[derive(Debug)]
struct CustomError(String);
impl Error for CustomError {}
impl std::fmt::Display for CustomError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
<Self as std::fmt::Debug>::fmt(self, f) // delegate to Debug
}
}
impl CustomError {
pub fn shout(&self) {
println!("{}", self.0);
}
}
fn boom() -> Result<(), Box<dyn Error>> {
// Err(String::from("string error").into())
Err(Box::new(CustomError("custom error".to_owned())))
}
fn main() {
let e = boom().unwrap_err();
if let Some(e) = e.downcast_ref::<CustomError>() {
e.shout();
} else {
println!("Other: {}", e)
}
}
view raw playground.rs hosted with ❤ by GitHub

Note that the String concrete type cannot be retrieved.

Playground link here.