【问题标题】:Rust Error conversion for generic FromStr, unwrap errors out with unsatisfied trait bounds通用 FromStr 的 Rust 错误转换,用不满足的特征边界解包错误
【发布时间】:2021-07-24 22:02:47
【问题描述】:

我正在使用thiserror crate 创建自定义错误类型

use thiserror::Error;

/// ParseTreeError enumerates all possible errors returned by this library.
#[derive(Error, Debug)]
pub enum ParseTreeError {
    /// Represents an empty source. For example, an empty text file being given
    /// as input to `count_words()`.
    #[error("Source contains no data")]
    EmptySource,

    /// Represents a failure to read from input.
    #[error("Read error")]
    ReadError,
}
pub struct Parser <'a, T>
where
    T: FromStr + PartialEq
{
    token_stream: &'a str,
    marker: (usize, usize),
}

impl<'a, T> Parser<'a, T>
where
    T: FromStr + PartialEq
{
    fn test_parse() -> Result<(), ParseTreeError> {
        let mut val = T::from_str("5").unwrap();
        Ok(())
    }
}

这会引发以下错误:

error[E0599]: the method `unwrap` exists for enum `std::result::Result<T, <T as FromStr>::Err>`, but its trait bounds were not satisfied
  --> src/tree/parser.rs:65:40
   |
65 |         let mut val = T::from_str("5").unwrap();
   |                                        ^^^^^^ method cannot be called on `std::result::Result<T, <T as FromStr>::Err>` due to unsatisfied trait bounds
   |
   = note: the following trait bounds were not satisfied:
           `<T as FromStr>::Err: Debug`

如果我像这样映射错误

let mut val2 = T::from_str("5").map_err(|_| ParseTreeError::ReadError).unwrap();

然后不会抛出错误。

如果我尝试使用 ?操作员我得到错误

error[E0277]: `?` couldn't convert the error to `ParseTreeError`
  --> src/tree/parser.rs:65:40
   |
65 |         let mut val1 = T::from_str("5")?;
   |                                        ^ the trait `From<<T as FromStr>::Err>` is not implemented for `ParseTreeError`
   |
   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
   = note: required by `from`

我需要做什么才能使 ? operator 可以自动将错误转换为正确的错误类型,而无需使用 map_err ?

【问题讨论】:

  • 要解包,您可以添加T::Err: Debug 绑定。要使用? 进行转换,您可以使用#[from] 注释,如thiserror 文档中所述。
  • @IbraheemAhmed 感谢您的建议,T::Err 是什么意思?所有类型都有吗?
  • 另外,我应该在哪个错误上使用#[from],是否存在所有 FromStr 实现都返回的常见错误?

标签: rust


【解决方案1】:

您的问题与thiserror 完全无关,但可以通过

use std::str::FromStr;

fn test_parse<T>() -> Result<(), ()>
where
    T: FromStr,
{
    let mut val = T::from_str("5").unwrap();
    Ok(())
}

那么,有什么问题吗?这个问题隐藏在Resultunwrap 中。 unwrap 只有在我们可以somehow show the E in Result&lt;T, E&gt; 时才可用:

//      vvvvvvvvvvvvv
impl<T, E: fmt::Debug> Result<T, E> {
    //    ...
    
    fn unwrap(self) -> T {
        ...
    }
}

E 来自哪里?好吧,每个FromStr 实现都必须定义相关的错误类型Err。但是,Err 没有任何限制。它可能实现Debug,但也可能不会。因为我们在test_parse 上的特征界限表明我们可以遍历所有仅实现FromStrTs,所以我们太笼统了。我们需要说test_parse 只适用于FromStrTs 其关联的Err 类型可以通过Debug 显示:

use std::fmt;
use std::str::FromStr;

fn test_parse<T>() -> Result<(), ()>
where
    T: FromStr,
    <T as FromStr>::Err: fmt::Debug,             // <<<<
{
    let mut val = T::from_str("5").unwrap();
    Ok(())
}

现在test_parse 不能再与所有可能的FromStr 实现一起使用,而只能用于在其关联的Err 类型上也实现Debug 的那些,这正是我们所需要的。

对于? 运算符,我们需要为ParseTreeError 实现From&lt;&lt;T as FromStr&gt;::Err&gt;,但是,that's blocked by E0207

【讨论】:

  • 被 E0207 阻止是什么意思?我查看了文档,似乎提出了一些解决方法。
  • 虽然它们看起来很复杂,我不得不手动实现它们,而不是依赖这个错误的#[from] 注释。
  • 我可以使 ParseTreeError Generic 避免 E0207 吗?
猜你喜欢
  • 2019-05-11
  • 1970-01-01
  • 2021-03-28
  • 2019-12-29
  • 2022-11-27
  • 2021-03-30
  • 2021-07-29
  • 2020-08-17
  • 2022-03-25
相关资源
最近更新 更多