如何在迭代器的收集语句中放置类型注释?

How to put a type annotation in an iterator's collect statement?

我有这个代码:

use std::fs::File;
use std::io::{BufRead, BufReader};

fn load_file() -> Vec<String> {
    let file = BufReader::new(File::open("foo.txt").unwrap());
    file.lines().map(|x| x.unwrap()).collect();
}

fn main() {
    let data = load_file();
    println!("DATA: {}", data[0]);
}

当我尝试编译它时,出现此错误:

error[E0283]: type annotations required: cannot resolve `_: std::iter::FromIterator<std::string::String>`
 --> src/main.rs:6:38
  |
6 |     file.lines().map(|x| x.unwrap()).collect();
  |                                      ^^^^^^^

事实上,如果我这样改变load_file函数,代码编译顺利:

fn load_file() -> Vec<String> {
    let file = BufReader::new(File::open("foo.txt").unwrap());
    let lines: Vec<String> = file.lines().map(|x| x.unwrap()).collect();
    return lines;
}

此解决方案 "Rusty" 不够,因为不鼓励以 return 结束函数。

有没有办法将类型注释直接放入 file.lines().map(|x| x.unwrap()).collect(); 语句中?

Iterator::collect's signature 看起来像这样:

fn collect<B>(self) -> B
where
    B: FromIterator<Self::Item>, 

在你的情况下,你需要告诉它 B 是什么。要指定通用函数的类型,您可以使用称为 turbofish 的语法,它看起来像 func::<T, U, ...>()

您的 load_file 函数应如下所示:

fn load_file() -> Vec<String> {
    let file = BufReader::new(File::open("foo.txt").unwrap());
    file.lines().map(|x| x.unwrap()).collect::<Vec<String>>()
}

您还可以通过将某些类型指定为占位符来允许某些类型推断继续 _:

fn load_file() -> Vec<String> {
    let file = BufReader::new(File::open("foo.txt").unwrap());
    file.lines().map(|x| x.unwrap()).collect::<Vec<_>>()
}

事实上,您的问题不太明显。这不会编译(您的初始代码):

use std::fs::File;
use std::io::{BufRead, BufReader};

fn load_file() -> Vec<String> {
    let file = BufReader::new(File::open("foo.txt").unwrap());
    file.lines().map(|x| x.unwrap()).collect();
}

fn main() {
    let data = load_file();
    println!("DATA: {}", data[0]);
}

但是这样做:

use std::fs::File;
use std::io::{BufRead, BufReader};

fn load_file() -> Vec<String> {
    let file = BufReader::new(File::open("foo.txt").unwrap());
    file.lines().map(|x| x.unwrap()).collect()
}

fn main() {
    let data = load_file();
    println!("DATA: {}", data[0]);
}

你能注意到细微的差别吗?只是load_file().

最后一行的一个分号而已

Rust 中的类型推断足够强大,这里不需要注解。您的问题在于您忽略了 collect() 的结果!对于类型推断,分号的作用类似于 "barrier",因为它没有连接 collect() 的 return 类型和 load_file() 的 return 类型。但是,该错误消息有些误导;似乎这个阶段的类型检查 运行 早于 return 类型的检查(这将正确地失败,因为 ()Vec<String> 不兼容)。