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

查看:178
本文介绍了有条件地从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<_>`

Playground Link

我知道我可以用一些嵌套的循环写一些我想要的东西,但是我想知道是否有一种简洁的方法来编写它使用迭代器。

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是静态类型的,因此迭代器链中的每个步骤都会将结果更改为一个新的类型,其中包含了以前的类型(除非你使用盒装特征对象)你必须以两种分支被相同类型覆盖的方式编写它。

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 元素的边缘情况使用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天全站免登陆