我有一个函数返回一个Result
:
fn find(id: &Id) -> Result<Item, ItemError> {
// ...
}
然后另一个使用它这样:
let parent_items: Vec<Item> = parent_ids.iter()
.map(|id| find(id).unwrap())
.collect();
如何处理任何map
迭代中的失败情况?
我知道我可以使用flat_map
,在这种情况下,错误结果将被 * 忽略 *:
let parent_items: Vec<Item> = parent_ids.iter()
.flat_map(|id| find(id).into_iter())
.collect();
Result
的迭代器根据成功状态有0或1项,如果为0,flat_map
将过滤掉它。
然而,我不想 * 忽略 * 错误,我想让整个代码块停止并返回一个新的错误(基于Map中出现的错误,或者只是转发现有的错误)。
在拉斯特我该怎么处理
4条答案
按热度按时间7lrncoxx1#
Result
实现了FromIterator
,因此您可以将Result
移到外部,迭代器将处理其余的工作(包括在发现错误时停止迭代)。Playground
50pmv0ei2#
可接受的答案显示了如何在 collecting 时在出错时停止,这很好,因为这是OP所要求的,如果您需要处理大型或无限的易出错迭代器,请继续阅读。
如前所述,
for
可以用来模拟错误停止,但有时候这并不优雅,比如当你想调用max()
或其他使用迭代器的方法时,在其他情况下这几乎是不可能的,比如迭代器被另一个机箱中的代码使用,比如itertools
或Rayon 1。迭代器使用者:
try_for_each
当你控制迭代器的使用方式时,你可以使用
try_for_each
在第一个错误时停止,它接受一个返回Result
的闭包,如果闭包每次都返回Ok
,try_for_each()
将返回Ok(())
。第一个Err
对应于第一个错误,这使得闭包可以通过自然的方式使用?
操作符来检测错误:如果需要维护闭包调用之间的状态,也可以使用
try_fold
,这两个方法都是由ParallelIterator
实现的,因此Rayon也可以使用相同的模式。try_for_each()
确实要求你控制迭代器的使用方式,如果这是由不受你控制的代码完成的--例如,如果你将迭代器传递给itertools::merge()
或类似的东西,你将需要一个适配器。迭代器适配器:
scan
出现错误时停止的第一次尝试是使用
take_while
:这是可行的,但是我们没有得到任何错误发生的指示,迭代只是安静地停止。而且它需要难看的
map(Result::unwrap)
,这使得程序看起来像是会在错误时崩溃,事实上我们在错误时停止并不是这样。这两个问题都可以通过从
take_while
切换到scan
来解决,scan
是一个更强大的组合子,它不仅支持停止迭代,而且传递它的回调拥有的项,允许闭包将错误提取到调用者:如果在多个地方需要,闭包可以抽象为一个效用函数:
...在这种情况下,我们可以将其作为
.scan(&mut err, until_err)
(playground)调用。这些例子用
for_each()
耗尽了迭代器,但是可以用任意操作链接它,包括Rayon的par_bridge()
。使用scan()
甚至可以将项collect()
到容器中,并访问错误前看到的项,这在收集到Result<Container, Error>
时有时是有用的,但不可用。1使用Rayon并行处理流数据时,需要使用
par_bridge()
:同样,通过收集到
Result
中不能轻易地实现等效效果。bjp0bcyl3#
处理嵌套的
.map()
闭包Result
如果
.map()
中的.map()
中有.map()
,会怎么样?下面是一个嵌套
.map()
操作的例子,它解决的问题是如何从最里面的闭包传播失败,同时避免使用.unwrap()
,因为.unwrap()
会中止应用程序。这种方法还支持在外层使用
?
语法,以便在出现错误时捕获错误,或者在未出现错误时展开结果并将其赋给变量。否则,?
不能在闭包内部使用。下面使用的
.parse()
将返回Result<T, ParseIntError>
。请注意,外部
.collect::<..>()
泛型表达式指定Result<Vec<Vec<..>>
。内部.collect()
将生成Result
,外部Result
在获取Ok
内容并生成2-D向量时将其剥离。如果不严重依赖类型推断,内部
.collect()
泛型表达式将如下所示:使用
?
语法,变量data
将被分配该2-D向量;或者main()
函数将返回源自内部闭包内的解析错误。输出:
更进一步,可以用这种方式处理嵌套三层的解析结果。
输出:
或者,如果一个数字不能被解析,我们会得到:
7hiiyaii4#
此答案与Rust 1.0之前的版本有关,所需功能已删除
你可以使用
std::result::fold
函数来完成这个任务,它会在遇到第一个Err
后停止迭代。我刚刚写的一个示例程序:
输出:
Demo