我有一个返回结果的函数
:
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
将过滤掉它。
但是,我不想忽略错误,而是想让整个代码块停止并返回一个新错误(基于映射中出现的错误,或者只是转发现有错误)。
在Rust中如何最好地处理此问题?
这个答案与Rust的1.0之前版本有关,所需的功能已被删除
您可以使用std::result::fold
函数进行此操作。遇到第一个Err
后,它停止迭代。
我刚刚编写的一个示例程序:
fn main() {
println!("{}", go([1, 2, 3]));
println!("{}", go([1, -2, 3]));
}
fn go(v: &[int]) -> Result<Vec<int>, String> {
std::result::fold(
v.iter().map(|&n| is_positive(n)),
vec![],
|mut v, e| {
v.push(e);
v
})
}
fn is_positive(n: int) -> Result<int, String> {
if n > 0 {
Ok(n)
} else {
Err(format!("{} is not positive!", n))
}
}
输出:
Ok([1, 2, 3])
Err(-2 is not positive!)
演示
接受的答案显示了如何在收集时停止出错,这很好,因为这是OP要求的。如果您需要在大型或无限容易出错的迭代器上进行处理,请继续阅读。
如前所述,for
可以用来模拟出错时停止,但这有时并不雅观,比如当您想调用max()
或其他消费方法时。在其他情况下,这几乎是不可能的,比如消费方法在另一个板条箱中,比如itertools
或人造丝1。
当您控制迭代器的使用方式时,只需使用try_for_each
在出现第一个错误时停止。它接受一个返回结果的闭包,如果闭包每次都返回Ok,并且第一个错误返回Err,则它将返回Ok(())。这使得闭包只需使用
运算符:
use std::{fs, io};
fn main() -> io::Result<()> {
fs::read_dir("/")?.try_for_each(|e| -> io::Result<()> {
println!("{}", e?.path().display());
Ok(())
})?;
// ...
Ok(())
}
如果需要在调用闭包之间保持状态,也可以使用
try\u fold
。这两种方法都是由并行迭代器实现的,所以同样的模式也适用于人造丝。
这种方法要求您控制迭代器的使用方式。如果这是由不受您控制的代码完成的——例如,如果您将迭代器传递给
itertools::mer()
或类似的,您将需要一个适配器。
出现错误时停止的第一次尝试是使用
take_while
:
use std::{io, fs};
fn main() -> io::Result<()> {
fs::read_dir("/")?
.take_while(Result::is_ok)
.map(Result::unwrap)
.for_each(|e| println!("{}", e.path().display()));
// ...
Ok(())
}
这是可行的,但我们没有得到任何错误发生的迹象,迭代只是静静地停止。此外,它还需要难看的
映射(Result::unwrap)
,这使得程序似乎会在出错时死机,而事实上,当我们在出错时停止时,情况并非如此。
这两个问题都可以通过从
take_while
切换到扫描
来修复,这是一个更强大的组合器,不仅支持停止迭代,还传递其回调拥有的项目,允许闭包将错误提取给调用者:
fn main() -> io::Result<()> {
let mut err = Ok(());
fs::read_dir("/")?
.scan(&mut err, |err, res| match res {
Ok(o) => Some(o),
Err(e) => {
**err = Err(e);
None
}
})
.for_each(|e| println!("{}", e.path().display()));
err?;
// ...
Ok(())
}
如果在多个地方需要,可以将闭包抽象为一个实用函数:
fn until_err<T, E>(err: &mut &mut Result<(), E>, item: Result<T, E>) -> Option<T> {
match item {
Ok(item) => Some(item),
Err(e) => {
**err = Err(e);
None
}
}
}
...在这种情况下,我们可以调用它作为
。扫描(
这些示例使用
for_each()
简单地耗尽迭代器,但可以通过任意操作将其链接,包括Rayon的par_bridge()
。使用scan()
甚至可以collect()
将项目收集到一个容器中,并访问错误之前看到的项目,这在收集到结果时有时很有用,但不可用
1在使用人造丝并行处理流数据时,需要使用
par_bridge()
出现:
fn process(input: impl BufRead + Send) -> std::Result<Output, Error> {
let mut err = Ok(());
let output = lines
.input()
.scan(&mut err, until_err)
.par_bridge()
.map(|line| ... executed in parallel ... )
.reduce(|item| ... also executed in parallel ...);
err?;
...
Ok(output)
}
同样,通过收集到
结果
中,也无法轻松实现等效效果。
Result
实现了迭代器的功能,因此您可以将
结果
移到外部,迭代器将处理其余部分(包括在发现错误时停止迭代)。
#[derive(Debug)]
struct Item;
type Id = String;
fn find(id: &Id) -> Result<Item, String> {
Err(format!("Not found: {:?}", id))
}
fn main() {
let s = |s: &str| s.to_string();
let ids = vec![s("1"), s("2"), s("3")];
let items: Result<Vec<_>, _> = ids.iter().map(find).collect();
println!("Result: {:?}", items);
}
游乐场
在spark中使用mapPartitionsToPair/PairFlatMapFunction时,我在Internet上找到了一个类似的例子 但当康普利 我找到了的声明 所以调用应该是返回一个迭代器。 因此,有人能帮助我如何返回在javaRDD api火花迭代器?谢谢 PS:我试过下面这样的代码,但在集群上不起作用:
我正在做一些产生正确结果的事情。然而,从设计观点来看,这是错误的。 该程序的重点是列出一个数字的所有幂的结果,直到并包括用户定义的限制。 我有一个构造函数,它接受扫描器中的基和指数。然后是一种利用for循环计算每个指数的幂的方法。 现在,问题是我直接从这个方法打印每个循环迭代的结果。这超过了私有变量的点,它首先是无效的。 因此,我想定义一个getter方法,它将每个幂的结果返回给输出。我过去常常为
我有个智囊团。我需要迭代并返回一个值! 我能和Lambda一起做这件事吗?怎么做?(如何获取具有类型_12项的组的id?类型_12项将在所有组中仅为一个) 提前致谢这是我的代码:
将这些视为对象: 查看java文档,对于LinkedList类,LinkedList类中没有迭代器方法的实现,但是,实现是在AbstractSequentialList类中。 listIterator()方法在AbstractList类中实现,AbstractSequentialList的父类,总结一下,如果我没弄错的话,它返回一个不使用节点概念的迭代器对象。 但是方法是在LinkedList类中
我可以看到返回。但是现在已经添加到C++20标准中,为什么返回?cppreference指定: 返回值 等于last的迭代器。 这个选择背后的理性是什么? 与相比,用例的优势是什么?
本文向大家介绍C++映射迭代器,包括了C++映射迭代器的使用技巧和注意事项,需要的朋友参考一下 示例 容器中第一个元素的迭代器。 如果映射对象是const限定符,则该函数返回const_iterator。否则,返回iterator。 输出: a => 200 b => 100 c => 300