【问题标题】:Implement a trait for another trait Item type为另一个特征项目类型实现一个特征
【发布时间】:2019-05-26 18:41:07
【问题描述】:

我需要在返回 Result 时将解析错误转换为我自己的错误类型。简化后如下所示:

enum MyError {
    Parse,
    ...,
}

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

为了使上述工作应该实现 From 特征。这不起作用:

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

编译器诊断:

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

但我不知道这里的确切 Type。重点是允许从所有可能的错误中进行转换。

【问题讨论】:

  • 如果不将MyError 设为通用,我认为这是不可能的。 FromStr::Err 不是具体类型,它是由FromStr 的实现指定的类型,这意味着您不能将它当作具体类型来引用。

标签: error-handling rust


【解决方案1】:

FromStr::Err 类型是FromStr 特征的关联类型FromStr 的每个实现都有它自己的关联类型,而且这种类型是完全不受约束的——它可以是任何类型。这意味着您需要从任何类型转换为 MyError 才能实现您想要的:

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

但是,一致性规则不允许此实现 - 它与标准库中任何类型 TFrom&lt;T&gt; 的实现相冲突。即使这个实现被允许,它也不会真正做你想要的——any 错误类型将被转换为MyError::Parse,而不仅仅是解析错误。

一种可能的解决方法是为解析错误类型引入标记特征:

trait ParseError {}

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

然后您可以为所有解析错误类型实现此标记特征:

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 {}

【讨论】:

    【解决方案2】:

    如果您仍然要丢弃解析错误,请使用 map_err 在本地更改错误:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-29
      • 1970-01-01
      • 2021-12-28
      • 1970-01-01
      • 2019-12-08
      • 1970-01-01
      相关资源
      最近更新 更多