This is a follow-up question on my previous question: Rust: Read and map lines from stdin and handling different error types
I have created the following struct and function to read lines from stdin and parse them into integers and it works:
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
}
Now, I thought that I would replace u32
for a type parameter T to allow for any kind of numeric type. To do this I assume that I need to restrict T to types implementing the FromStr trait and then somehow implement the From trait to allow conversion from FromStr::Err into my "InputError".
Following the error I first got
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`
I tried something like this:
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)
}
}
But that instead results in:
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
So basically what I want to express is something along the lines of: "I want to implement the trait From<T::Err>
for my InputError
for every T
which also implements FromStr
. Is this even possible and if so, how?
So basically what I want to express is something along the lines of: "I want to implement the trait
From<T::Err>
for myInputError
for everyT
which also implementsFromStr
. Is this even possible and if so, how?
This isn't what the error is saying.
The trait FromStr
has an associated type, Err
. The error is saying that this associated error type cannot be converted to InputError
.
First, let's simplify by getting rid of the type parameters:
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
}
This works!
The associated Err
type for u32
's FromStr
implementation is ParseIntError
and you have correctly implemented From<ParseIntError> for InputError
.
The reason this doesn't work for T
is because T
's FromStr::Err
type could be anything. By using a type parameter, you are telling the compiler that you expect this function to work for any possible type T
, but it only works for types where FromStr::Err
can be converted to your InputError
type.
The error message gives you a hint:
= help: consider adding a `where InputError: std::convert::From<<T as std::str::FromStr>::Err>` bound
So let's do that:
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
}
This tells the compiler that you expect the function to work for all possible T
provided that :
T
implements FromStr
and, Err
type from T
's FromStr
implementation can be converted into an InputError
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.