我正在尝试创建一个简单的实用程序函数,它从stdin
读取多个元素并将它们放入集合中并返回它。但是我在这一点上陷入困境。编译器说missing associated type Err value
。如何使其工作,同时尽可能保持通用?
虽然这个功能似乎没用,但是它用于学习语言及其类型系统。
use std::io::{ stdin };
use std::str::FromStr;
use std::io::Read;
use std::iter::FromIterator;
pub fn read_all<C>() -> C
where C: FromIterator<FromStr<Err>>
{
let mut buff = String::new();
stdin().read_to_string(&mut buff).expect("read_to_string error");
buff.split_whitespace()
.filter_map(|w| w.parse().ok())
.collect()
}
用法示例:
let v: Vec<i32> = read_all();
答案 0 :(得分:6)
为了使其编译,您需要更改为代码的唯一方法是函数的类型签名:
pub fn read_all<C, F>() -> C
where F: FromStr,
C: FromIterator<F>
您的代码几乎正确,但存在问题:
FromIterator<T>
是一种特质,但T
是类型。FromStr
的位置使用T
,但FromStr
是特质,而不是类型。要解决此问题,您需要获得实现FromStr
的类型。您可以通过向函数添加类型参数F
并使用where F: FromStr
约束它来执行此操作。然后你可以写FromIterator<F>
。
除了使用特征而不是类型的问题之外,输入FromStr<Err>
语法是错误的。虽然在这种情况下没有必要在Err
特征中指定FromStr
的类型,但您可以执行以下操作:
pub fn read_all<C, F, E>() -> C
where F: FromStr<Err=E>,
C: FromIterator<F>
正如您所看到的,我们需要编写FromStr<E>
而不是写FromStr<Err=E>
。也就是说,您需要显式键入要引用的关联类型的名称。
通常,traits不能被视为类型。但是,此规则有例外情况,如下例所示:
use std::fmt::Display;
pub fn print_box(thing: Box<Display>) {
println!("{}", thing)
}
fn main() { print_box(Box::new(42)); }
在这里,您希望T
中的Box<T>
成为一种类型,但会提供Display
特征。但是,编译器不会拒绝该程序。类型检查器将Display
视为unsized type。也就是说,在编译时具有未知大小的对象的类型(因为它可以是实现Display
的任何类型)。如果T
中的Box<T>
是特征,则生成的类型通常称为trait object。这里不可能深入讨论这个主题,但我想提到的链接是一个很好的起点,以防你想了解更多。