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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
} |
Note that the String
concrete type cannot be retrieved.
Playground link here.