Search code examples
rust

Type annotations needed when trying to display parse error in rust


rustc says: "error[E0282]: type annotations needed"

pub fn parse<T: std::str::FromStr>(v: &str) -> T {
    match v.parse() {
        Err(e) => {
            panic!(
                "Error when parsing to type {}. {} Value: '{}' ",
                std::any::type_name::<T>(),
                e.to_string(),
//  Error:      ^ cannot infer type
                v
            )
        }
        Ok(r) => r
    }
}

Can I check whether the Error e implements Display and only then print it?


Solution

  • Calling .to_string() here is redundant and causes an extra, unnecessary allocation compared to simply formatting e. Remove the .to_string() call, and add the bound T::Err: Display.

    Consider also formatting v using debug formatting so that unprintable characters are displayed as escape sequences.

    use std::{fmt::Display, str::FromStr};
    
    pub fn parse<T>(v: &str) -> T
    where
        T: FromStr,
        T::Err: Display,
    {
        match v.parse() {
            Err(e) => {
                panic!(
                    "Error when parsing to type {}. {} Value: {:?}",
                    std::any::type_name::<T>(),
                    e,
                    v
                )
            }
            Ok(r) => r,
        }
    }
    

    As far as why the error occurs, it's because the compiler doesn't yet know what type is being parsed. That is, when you call v.parse(), the return type is not yet fully known. The compiler only knows that it must be Result<_, _>. It becomes fully known when the Ok(r) => r arm is seen; since r is being returned from the function, the compiler can then infer that v.parse() returns Result<T, T::Err>, and therefore e must be T::Err.

    Resolving that inference error is as easy as swapping the arms around so that the Ok case is handled first. This way, the compiler knows what e must be when e.to_string() is reached. Fixing that error will reveal the missing Display bound:

    error[E0599]: `<T as FromStr>::Err` doesn't implement `std::fmt::Display`
    

    This error could be fixed with the same where clause provided above.