[英]How do I flatten an iterator of Result<Vec<T>,E> to return an iterator of Result<T,E> in rust?
这是我的测试用例; 由于不兼容的匹配臂,它无法编译。 我应该如何解决这个问题,或者在这里获得扁平迭代器的更好方法是什么?
fn main() {
let v1: Vec<Result<Vec<u32>, &str>> = vec![ Ok(vec![1,2,3]), Ok(vec![4,5,6,9]), Err("failed"), ];
let iter1 = v1.iter();
let flattened_iter1 = iter1.map(|x| match x {
Ok(v) => v.iter().map(|v| Ok(v)),
Err(e) => once(Err(e)),
}).flatten();
for r in flattened_iter1 {
match r {
Ok(i) => println!("{}", i),
Err(i) => { println!("Error"); break },
}
}
}
一种选择是使用提供Either<L, R>
枚举的 Either either
。 一个Either<L, R>
可以是Either::Left(L)
或Either::Right(R)
,当L
和R
都用相同的Iterator::Item
实现Iterator
时, Either<L, R>
实现Iterator
本身类型。
这为您提供了与盒装特征对象类似的灵活性,但没有堆分配的开销。 仍然存在动态调度,但由Either
在内部作为条件而不是函数指针调用处理。
use std::iter::once;
use either::Either;
fn main() {
let v1: Vec<Result<Vec<u32>, &str>> = vec![ Ok(vec![1,2,3]), Ok(vec![4,5,6,9]), Err("failed"), ];
let iter1 = v1.iter();
let flattened_iter1 = iter1.map(|x| match x {
Ok(v) => Either::Left(v.iter().map(|v| Ok(v))),
Err(e) => Either::Right(once(Err(e))),
}).flatten();
for r in flattened_iter1 {
match r {
Ok(i) => println!("{}", i),
Err(i) => { println!("Error"); break },
}
}
}
( 游乐场)
这是行不通的,因为map
和once
会产生两种不同的类型。 你想要的方式是告诉 Rust 你并不真正关心它们是不同的类型,你唯一关心的是它们都是迭代器。 为此,您可以将它们显式地转换为特征对象once(Err(e)) as dyn Iterator<Item=Result<u32, &str>>
,但这不起作用,因为 Rust 在编译时无法知道它们的大小时间。 为了使其工作,您需要将它们分配在堆上而不是堆栈上,从而导致
use std::iter::once;
fn main() {
let v1 = vec![ Ok(vec![1,2,3]), Ok(vec![4,5,6,9]), Err("failed"), ];
let flattened_iter1 = v1
.iter()
.map(|x| match x {
Ok(v) => Box::new(v.iter().map(|v| Ok(v))) as Box<dyn Iterator<Item=_>>,
Err(e) => Box::new(once(Err(e))) as Box<dyn Iterator<Item=_>>,
})
.flatten();
for r in flattened_iter1 {
match r {
Ok(i) => println!("{}", i),
Err(i) => { println!("Error"); break },
}
}
}
你可以在操场上试试这个。
这种方法有几点需要注意:
Box
的东西不是免费的,因为它会导致实际分配,但它也不是超级昂贵。 与您将所有内容收集到单个Vec
以对其进行迭代的解决方案相比,这可能更便宜;Item
,因为 Rust 能够自己找出它。虽然在一般情况下我会使用either
一板条箱,但在这种特定情况下, itertools
已经让您使用flatten_ok()
:
use itertools::Itertools;
let flattened_iter1 = iter1.map(Result::as_ref).flatten_ok();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.