从 flat_map 有条件地返回空迭代器 [英] Conditionally return empty iterator from flat_map
问题描述
鉴于 foo
的这个定义:
let foo = vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];
我希望能够编写这样的代码:
I'd like to be able to write code like this:
let result: Vec<_> = foo.iter()
.enumerate()
.flat_map(|(i, row)| if i % 2 == 0 {
row.iter().map(|x| x * 2)
} else {
std::iter::empty()
})
.collect();
但这会引发关于 if 和 else 子句类型不兼容的错误.我尝试暂时删除 map
并尝试在闭包之外定义一个空向量并返回一个迭代器,如下所示:
but that raises an error about the if and else clauses having incompatible types. I tried removing the map
temporarily and I tried defining an empty vector outside the closure and returning an iterator over that like so:
let empty = vec![];
let result: Vec<_> = foo.iter()
.enumerate()
.flat_map(|(i, row)| if i % 2 == 0 {
row.iter() //.map(|x| x * 2)
} else {
empty.iter()
})
.collect();
这看起来有点傻,但它可以编译.如果我尝试取消注释 map
那么它仍然会抱怨 if 和 else 子句具有不兼容的类型.以下是错误消息的一部分:
This seems kind of silly but it compiles. If I try to uncomment the map
then it still complains about the if and else clauses having incompatible types. Here's part of the error message:
error[E0308]: if and else have incompatible types
--> src/main.rs:6:30
|
6 | .flat_map(|(i, row)| if i % 2 == 0 {
| ______________________________^
7 | | row.iter().map(|x| x * 2)
8 | | } else {
9 | | std::iter::empty()
10 | | })
| |_________^ expected struct `std::iter::Map`, found struct `std::iter::Empty`
|
= note: expected type `std::iter::Map<std::slice::Iter<'_, {integer}>, [closure@src/main.rs:7:28: 7:37]>`
found type `std::iter::Empty<_>`
我知道我可以用一些嵌套的 for
循环写出我想要的东西,但我想知道是否有一种使用迭代器的简洁方法来编写它.
I know I could write something that does what I want with some nested for
loops but I'd like to know if there's a terse way to write it using iterators.
推荐答案
由于 Rust 是静态类型的,并且迭代器链中的每一步都会将结果更改为包含先前类型的新类型(除非您使用盒装 trait 对象),您必须以两个分支都被相同类型覆盖的方式编写它.
Since Rust is statically typed and each step in an iterator chain changes the result to a new type that entrains the previous types (unless you use boxed trait objects) you will have to write it in a way where both branches are covered by the same types.
用单一类型表达条件空虚的一种方法是 TakeWhile
迭代器实现.
One way to convey conditional emptiness with a single type is the TakeWhile
iterator implementation.
.flat_map(|(i, row)| {
let iter = row.iter().map(|x| x * 2);
let take = i % 2 == 0;
iter.take_while(|_| take)
})
如果你不介意忽略输入迭代器 foo
可能有多个 usize
元素的边缘情况,你也可以使用 Take
而不是 0 或 usize::MAX.它的优点是提供了比 TakeWhile
更好的 size_hint()
.
If you don't mind ignoring the edge-case where the input iterator foo
could have more than usize
elements you could also use Take
instead with either 0 or usize::MAX. It has the advantage of providing a better size_hint()
than TakeWhile
.
这篇关于从 flat_map 有条件地返回空迭代器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!