简体   繁体   中英

Implement a trait for another trait Item type

I need to convert a parse error to my own Error type while returning Result. Simplified, it looks like the following:

enum MyError {
    Parse,
    ...,
}

fn process<R: FromStr>(s: &str) -> Result<(), MyError> {
    Ok(s.parse::<R>()?)
}

For above to work From trait should be implemented. This doesn't work:

impl From<std::str::FromStr::Err> for MyError {
    fn from(e: std::str::FromStr::Err) -> MyError {
        MyError::Parse
    }
}

The compiler diagnostics:

help: use fully-qualified syntax: `<Type as std::str::FromStr>::Err`

But I don't know the exact Type here. The whole point is to allow conversion from all possible errors.

The type FromStr::Err is an associated type of the FromStr trait. Every implementation of FromStr has its own associated type, and this type is completely unconstrained – it could be any type at all. This means you would need a conversion from any type to MyError to achieve what you want:

impl<T> From<T> for MyError {
    fn from(e: T) -> MyError {
        MyError::Parse
    }
}

However, this implementation is disallowed by the coherence rules – it conflicts with the implementation of From<T> for any type T in the standard library. And even if this implementation was allowed, it wouldn't really do what you want – any error type would be converted to MyError::Parse , not just parse errors.

One possible workaround is to introduce a marker trait for parse error types:

trait ParseError {}

impl<T: ParseError> From<T> for MyError {
    fn from(e: T) -> MyError {
        MyError::Parse
    }
}

You can then implement this marker trait for all parse error types:

impl ParseError for std::str::ParseBoolError {}
impl ParseError for std::num::ParseFloatError {}
impl ParseError for std::num::ParseIntError {}
impl ParseError for std::net::AddrParseError {}
impl ParseError for std::char::ParseCharError {}

If you're discarding the parse error anyway, use map_err to change the error locally:

fn process<R: FromStr>(s: &str) -> Result<(), MyError> {
    let _ = s.parse::<R>().map_err(|_| MyError::Parse)?;
    Ok(())
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM