从 flat_map 有条件地返回空迭代器 [英] Conditionally return empty iterator from flat_map

查看:19
本文介绍了从 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆