Rust:为相关类型实现特征“从”(错误)

时间:2019-12-06 13:34:52

标签: rust traits

这是我上一个问题的后续问题:Rust: Read and map lines from stdin and handling different error types

我创建了以下结构和函数以从stdin中读取行并将其解析为整数,并且可以正常工作:

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
}

现在,我想我将u32替换为类型参数T,以允许使用任何类型的数字类型。为此,我假设我需要将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

所以基本上我想表达的是以下内容: “我想为每个From<T::Err>的{​​{1}}实现特征InputError,同时也实现T。这是否可能?如果可以,怎么办?

1 个答案:

答案 0 :(得分:2)

  

所以基本上我想表达的是以下内容:   “我想为每个From<T::Err>的{​​{1}}实现特征InputError,同时也实现T。这是否可能?如果可以,怎么办?

这不是错误的意思。

特征FromStr具有关联的类型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 } 的{​​{1}}实现相关的Err类型为u32,您已经正确实现了FromStr

这不适用于ParseIntError的原因是因为From<ParseIntError> for InputError的{​​{1}}类型可以是任何东西。通过使用类型参数,您告诉编译器您希望该函数可用于任何可能的类型T,但仅适用于可以转换T的类型设置为您的FromStr::Err类型。

错误消息给您提示:

T

让我们这样做:

FromStr::Err

这告诉编译器,您希望该函数对所有可能的InputError有效,前提是{em>

  • = 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的{​​{1}}实现中关联的T类型转换为FromStr