我正在尝试创建一个通用函数来从stdin中读取一个数字:
use std::error::Error;
use std::io;
use std::io::Write;
use std::str::FromStr;
fn read_number<F: FromStr>(prompt: &str) -> Result<F, Box<Error>> {
let mut guess = String::new();
let mut sout = io::stdout();
sout.write(prompt.as_bytes())?;
sout.flush()?;
io::stdin().read_line(&mut guess)?;
Ok(guess.trim().parse()?)
}
fn read_until_number<F: FromStr>(prompt: &str) -> F {
loop {
match read_number(prompt) {
Ok(num) => break num,
Err(_) => println!("Please enter valid number."),
};
}
}
fn main() {
let x: u32 = read_until_number("Enter integer:\n");
let y: f32 = read_until_number("Enter float:\n");
println!("You entered this integer: {} and this float: {}", x, y);
}
它不起作用;我收到以下错误:
error[E0277]: the trait bound `<F as std::str::FromStr>::Err: std::error::Error` is not satisfied
--> src/main.rs:16:8
|
16 | Ok(guess.trim().parse()?)
| ^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `<F as std::str::FromStr>::Err`
|
= help: consider adding a `where <F as std::str::FromStr>::Err: std::error::Error` bound
= note: required because of the requirements on the impl of `std::convert::From<<F as std::str::FromStr>::Err>` for `std::boxed::Box<std::error::Error>`
= note: required by `std::convert::From::from`
答案 0 :(得分:3)
错误消息告诉您该怎么做:
consider adding a `where <F as std::str::FromStr>::Err: std::error::Error` bound
遵循建议,但使用更简单的语法:
fn read_number<F>(prompt: &str) -> Result<F, Box<Error>>
where
F: FromStr,
F::Err: std::error::Error,
这会导致另一个错误,它也会告诉您该怎么做:
error[E0310]: the associated type `<F as std::str::FromStr>::Err` may not live long enough
--> src/main.rs:20:8
|
20 | Ok(guess.trim().parse()?)
| ^^^^^^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `<F as std::str::FromStr>::Err: 'static`...
note: ...so that the type `<F as std::str::FromStr>::Err` will meet its required lifetime bounds
--> src/main.rs:20:8
|
20 | Ok(guess.trim().parse()?)
| ^^^^^^^^^^^^^^^^^^^^^
根据建议并将其添加到我们现有的限制中:
fn read_number<F>(prompt: &str) -> Result<F, Box<Error>>
where
F: FromStr,
F::Err: std::error::Error + 'static,
然后,您将获得read_until_number
函数的相同错误。重复相同的过程,最终得到:
use std::error::Error;
use std::io;
use std::io::Write;
use std::str::FromStr;
fn read_number<F>(prompt: &str) -> Result<F, Box<Error>>
where
F: FromStr,
F::Err: std::error::Error + 'static,
{
let mut guess = String::new();
let mut sout = io::stdout();
sout.write(prompt.as_bytes())?;
sout.flush()?;
io::stdin().read_line(&mut guess)?;
Ok(guess.trim().parse()?)
}
fn read_until_number<F>(prompt: &str) -> F
where
F: FromStr,
F::Err: std::error::Error + 'static,
{
loop {
match read_number(prompt) {
Ok(num) => break num,
Err(_) => println!("Please enter valid number."),
};
}
}
fn main() {
let x: u32 = read_until_number("Enter integer:\n");
let y: f32 = read_until_number("Enter float:\n");
println!("You entered this integer: {} and this float: {}", x, y);
}
为什么需要这个?
implementation of From
for Box<Error>
要求类型实现std::error::Error
,但特征FromStr
对关联的Err
类型没有限制。您必须向您的函数添加限制才能执行转换。
默认情况下,参数位置的特征对象具有隐式'static
界限,就像您完成Box<Error + 'static>
一样。您可以更改read_number
以使用更细微的生命周期,但您无法更改read_until_number
,因为错误必须在函数之外生效:
fn read_number<'a, F>(prompt: &'a str) -> Result<F, Box<Error + 'a>>
where
F: FromStr,
F::Err: std::error::Error + 'a,