rust 避免collect()上的turbofish类型标注到Result&lt;Vec< _>,_&gt;

r3i60tvu  于 9个月前  发布在  其他
关注(0)|答案(2)|浏览(115)

我想使用collect() a iterator of Result<T, E> s into a Vec<T> and early-return以防迭代器中的任何元素出错。所以,类似于这样:

use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    let input = ""; // Snip real input
    let games: Vec<Game> = input.lines().map(parse_game).collect()?;
    println!("parsed {} games", games.len());
    Ok(())
}

struct Game;

fn parse_game(_s: &str) -> Result<Game, Box<dyn Error>> {
    Ok(Game)
}

字符串
Playground link,是的,代码的灵感来自于代码2023第2天的到来)
但这不起作用,它无法编译,并出现错误:

error[E0282]: type annotations needed
 --> src/main.rs:5:58
  |
5 |     let games: Vec<Game> = input.lines().map(parse_game).collect()?;
  |                                                          ^^^^^^^ cannot infer type of the type parameter `B` declared on the method `collect`
  |
help: consider specifying the generic argument
  |
5 |     let games: Vec<Game> = input.lines().map(parse_game).collect::<Vec<_>>()?;
  |                                                                 ++++++++++


如果我添加类型注解以在collect()上使用正确的impl FromIterator,它就可以工作:

let games: Vec<Game> = input.lines().map(parse_game).collect::<Result<_, _>>()?;


Playground link
但是我不明白为什么::<Result<_, _>>的turbofish类型注解是必要的,而且我觉得它非常多余和嘈杂。
我希望Rust编译器知道parse_game返回Result s,如果我想收集到Vec<Game>中,(由games变量类型指定),我在返回Result的函数上使用?运算符提前返回(main()),那么collect()调用也应该返回Result,因此不需要显式的类型注解。
那么,有没有一种方法可以去掉这个turbofish类型注解呢?或者用其他的习惯表达方式?

6yt4nkrj

6yt4nkrj1#

有很多方法可以去掉turbofish,但你不会喜欢它们。第一种方法是使用一个中间变量。

let games_result: Result<_, _> = input.lines().map(parse_game).collect();
let games: Vec<Game> = games_result?;

字符串
第二种方法是使用collect的内部trait函数FromIterator::from_iter

let games: Vec<Game> = Result::from_iter(input.lines().map(parse_game))?;


第一个在噪音方面没有提供任何比turbofish更好的改进,第二个失去了collect的功能风格。
不幸的是,我不认为有更好的方法来避免collect的turbofish,然而,itertools crate提供了try_collect,它可以满足你的需要。

use itertools::Itertools;
let games: Vec<Game> = input.lines().map(parse_game).try_collect()?;

mf98qq94

mf98qq942#

我刚刚了解到有一个proposal for Iterator::try_collect()可以做到这一点,并且可以在Rust上每晚使用,作为一个不稳定的功能:

#![feature(iterator_try_collect)]
// And then:
let games: Vec<_> = input.lines().map(parse_game).try_collect()?;

字符串
Playground link
这不适用于那些只想使用稳定Rust的人(比如我),但如果你已经每晚都在使用,这可能是一个方便的功能。

相关问题