如何解决“缺少关联类型`Err`值”错误?

时间:2016-12-25 11:19:00

标签: rust

我正在尝试创建一个简单的实用程序函数,它从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();

1 个答案:

答案 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。这里不可能深入讨论这个主题,但我想提到的链接是一个很好的起点,以防你想了解更多。