Rust:为关联类型(Error)实现trait“From”

3
这是我之前问题的后续问题:Rust:读取并映射来自标准输入的行并处理不同的错误类型 我创建了以下结构体和函数,用于从标准输入读取行并将它们解析为整数,目前它能正常工作。
use std::io::BufRead;
use std::{io, num, str};

#[derive(Debug)]
enum InputError {
    IOError(io::Error),
    ParseIntError(num::ParseIntError),
}

impl From<io::Error> for InputError {
    fn from(e: io::Error) -> InputError {
        return InputError::IOError(e);
    }
}

impl From<num::ParseIntError> for InputError {
    fn from(e: num::ParseIntError) -> InputError {
        return InputError::ParseIntError(e);
    }
}

pub fn get_integer_lines<T>() -> Result<Vec<T>, InputError>
where
    T: str::FromStr,
{
    let stdin = io::stdin();
    let my_values: Result<Vec<_>, InputError> = stdin
        .lock()
        .lines()
        .map(|line| -> Result<T, InputError> { Ok(line?.parse::<T>()?) })
        .collect();
    my_values
}

现在,我想把类型参数T替换为u32,以允许使用任何一种数字类型。为了做到这一点,我假设需要将T限制为实现FromStr特性的类型,然后以某种方式实现From特性,以允许从FromStr :: Err转换为我的“InputError”。根据错误信息,我首先得到了以下提示:
error[E0277]: `?` couldn't convert the error to `InputError`
  --> src/lib.rs:30:69
   |
30 |         .map(|line| -> Result<T, InputError> { Ok(line?.parse::<T>()?) })
   |                                                                     ^ the trait `std::convert::From<<T as std::str::FromStr>::Err>` is not implemented for `InputError`
   |
   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
   = help: consider adding a `where InputError: std::convert::From<<T as std::str::FromStr>::Err>` bound
   = note: required by `std::convert::From::from`

我尝试了类似这样的东西:
impl std::convert::From<<T as std::str::FromStr>::Err> for InputError {
    fn from(e: <T as std::str::FromStr>::Err) -> InputError {
        return InputError::ParseIntError(e)
    }
} 

但是这会导致以下结果:
error[E0412]: cannot find type `T` in this scope
  --> src/lib.rs:22:26
   |
22 | impl std::convert::From<<T as std::str::FromStr>::Err> for InputError {
   |                          ^ not found in this scope

基本上我想表达的意思是:

我想为每个实现FromStrT类型,实现InputError的特性From<T::Err>。这是否可能,如果可能,怎么做呢?

1个回答

4
所以基本上我想表达的是: “我想为所有实现了FromStr trait的T实现From<> trait,用于我的InputError。这是否可能,如果可能,该如何实现?”
这不是错误信息所说的问题。
trait FromStr 有一个关联类型 Err。该错误提示无法将此关联错误类型转换为 InputError。
首先,让我们通过去掉类型参数来简化问题:
fn get_integer_lines() -> Result<Vec<u32>, InputError> {
    let stdin = io::stdin();
    let my_values = stdin
        .lock()
        .lines()
        .map(|line| Ok(line?.parse()?))
        .collect();
    my_values
}

这是有效的代码!

u32FromStr 实现相关的错误类型是 ParseIntError,而您已经正确实现了 From<ParseIntError> for InputError

而对于 T,它的 FromStr::Err 类型有可能是任何类型。通过使用类型参数,您告诉编译器您希望该函数适用于任何可能的类型 T,但实际上它仅适用于能将 FromStr::Err 转换为您的 InputError 类型的类型。

错误消息给出了提示:

= help: consider adding a `where InputError: std::convert::From<<T as std::str::FromStr>::Err>` bound

那么让我们开始吧:

fn get_integer_lines<T>() -> Result<Vec<T>, InputError>
where
    T: str::FromStr,
    InputError: From<<T as str::FromStr>::Err>,
{
    let stdin = io::stdin();
    let my_values = stdin
        .lock()
        .lines()
        .map(|line| Ok(line?.parse()?))
        .collect();
    my_values
}

这告诉编译器你期望函数适用于所有可能的,前提是
  • T实现了FromStr接口,并且
  • TFromStr实现中关联的Err类型可以转换成InputError

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接