Best way to deal with multiple error types

Usually, there are two ways to deal with this:

  1. 'Erase' the type by using dyn Error:
    fn main() -> Result<(), Box<dyn std::error::Error>> {
        let x = f1()?;
        let y = f2()?;
        let z = f3()?;
        Ok(())
    }
    
    This is useful if you only care about the message the errors might return, and not their actual type.
  2. Create an enum that contains the 3 types:
    enum MyError {
        Error1(Error1),
        Error2(Error2),
        Error3(Error3),
    }
    
    impl From<Error1> for MyError { ... }
    impl From<Error2> for MyError { ... }
    impl From<Error3> for MyError { ... }
    
    fn main() -> Result<(), MyError> {
        let x = f1()?;
        let y = f2()?;
        let z = f3()?;
        Ok(())
    }
    
    Since this is a bit tedious, you can use the crate thiserror to make the process easier :slightly_smiling_face: