【问题标题】:Cannot infer type for `B` for filter_map().sum()无法为 filter_map().sum() 推断“B”的类型
【发布时间】:2018-12-19 08:56:03
【问题描述】:

下面的代码读取数字,对它们求和,然后打印总和。我尝试了一些注释,但没有成功。我肯定错过了什么。我怎样才能让它工作?

use std::io;
use std::io::Read;

fn main() {
    let mut buff = String::new();
    io::stdin().read_to_string(&mut buff).expect("read_to_string error");

    let v: i32 = buff
        .split_whitespace()
        .filter_map(|w| w.parse().ok())
        .sum();

    println!("{:?}", v);
}

来自编译器的错误消息:

type annotations needed
 --> src\main.rs:9:10
  |
9 |         .filter_map(|w| w.parse().ok())
  |          ^^^^^^^^^^ cannot infer type for `B`

【问题讨论】:

    标签: parsing types rust type-inference


    【解决方案1】:

    快速解决方法是说出您要解析的类型:

    let v: i32 = buff
        .split_whitespace()
        .filter_map(|w| w.parse::<i32>().ok())
        .sum();
    

    原因是filter_map 有一个类型变量B,它需要从你传递给它的闭包中推断出来(闭包返回Option&lt;B&gt;)。但是,parse() 也有一个类型变量,用于您要解析的类型,通常也可以推断出来。但是在这里,类型检查器必须相互推断这些类型中的每一个,这显然是做不到的。要打破这个循环,你必须在某个地方告诉它具体类型是什么。

    您也可以通过注释 filter_map 来修复它。这不是很好,因为filter_map 有两个类型参数,但您仍然可以使用_ 来推断第二个:

    let v: i32 = buff
        .split_whitespace()
        .filter_map::<i32, _>(|w| w.parse().ok())
        .sum();
    

    【讨论】:

    • 我将编译器消息解释为“我必须注释 filter_map”,我没想到它是关于 parse。谢谢。
    • 我添加了更多解释。您也可以注释filter_map,但看起来会不太愉快。
    • 我之前尝试过类似 .filter_map 的东西,让我很困惑,呵呵
    • @DulguunOtgon 第二个参数是函数类型。因此,最好推断它。
    • 很确定.ok() 是多余的,因为Result 实现IntoIterator 就像Option 一样。哦,那是如果你切换到flat_map,没关系。 (我还是更喜欢flat_map)。
    【解决方案2】:

    让我们看看 filter_map 的签名,看看抱怨是什么:

    fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F> where F: FnMut(Self::Item) -> Option<B>, 
    

    好的,所以Option&lt;B&gt; 是结果,这意味着他无法推断w.parse().ok() 将是什么。

    让我们试着给他一个提示

    .filter_map(|w| w.parse::<i32>().ok())
    

    让我们编译看看....万岁!

    因此,经验教训:查找签名并尝试找出编译器无法推断的部分并尝试指定它。

    【讨论】:

    • 我们确实写了v : i32,那为什么编译器不能推断出来呢?
    • 因为您将其作为 sum 函数的提示。如果只写let v = ...,则必须指定 sum .sum::&lt;i32&gt;() 的类型。
    • 但是如果编译器知道.sum的类型,为什么不能推断.parse的类型呢? rustc 只能在那个层面做推论吗?
    • 因为它们可能不同,例如 w.parse::&lt;u32&gt;().sum::&lt;u64&gt;()
    • @hellow:我认为这不是原因。 w.parse::&lt;u32&gt;().sum::&lt;u64&gt;() will not compile。我认为这与sum() 不返回求和类型(称为Item)但任何实现Sum&lt;Item&gt; 的值有关。并且编译器失败了,因为可以应用任意数量的类型。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 1970-01-01
    • 2022-08-03
    • 1970-01-01
    • 1970-01-01
    • 2018-02-25
    相关资源
    最近更新 更多