无法在for循环内使用链式方法

Unable to use chain method inside of for loop

据我了解,在迭代器上调用 chain 方法会消耗它和 returns 一种新类型。这是一个问题,因为我需要在一个 for 循环中将多个迭代器链接在一起。我的第一次尝试:

pub fn convert(s: String, num_rows: i32) -> String {
    let mut iter = s.chars().enumerate().filter_map(|(i, c)| {
        if i % ((num_rows as usize - 1)*2) == 0 {Some(c)} else {None}});
    for n in 1..num_rows as usize {
        iter = iter.chain(
            s.chars().enumerate().filter_map(|(i,c)| {
                let cycle = (num_rows as usize - 1)*2;
                if i % cycle == n || i % cycle == cycle - n {Some(c)} else {None}
            })
        );
    }
    iter.collect()
}

这给了我一个错误:

error[E0308]: mismatched types
  --> src/lib.rs:5:16
   |
2  |       let mut iter = s.chars().enumerate().filter_map(|(i, c)| {
   |  _____________________________________________________-
3  | |         if i % ((num_rows as usize - 1)*2) == 0 {Some(c)} else {None}});
   | |                                                                      -
   | |                                                                      |
   | |______________________________________________________________________the expected closure
   |                                                                        the found closure
4  |       for n in 0..num_rows as usize {
5  |           iter = iter.chain(
   |  ________________^
6  | |             s.chars().enumerate().filter_map(|(i,c)| {
7  | |                 let cycle = (num_rows as usize - 1)*2;
8  | |                 if i % cycle == n || i % cycle == cycle - n {Some(c)} else {None}
9  | |             })
10 | |         );
   | |_________^ expected struct `FilterMap`, found struct `std::iter::Chain`
   |
   = note: expected struct `FilterMap<Enumerate<Chars<'_>>, _>`
              found struct `std::iter::Chain<FilterMap<Enumerate<Chars<'_>>, _>, FilterMap<Enumerate<Chars<'_>>, [closure@src/lib.rs:6:46: 9:14]>>`

没什么大不了的,我想。我将让它推断循环内的类型,如下所示:

pub fn convert(s: String, num_rows: i32) -> String {
    let mut iter;
    for n in 0..num_rows as usize {
        iter = iter.chain(
            s.chars().enumerate().filter_map(|(i,c)| {
                let cycle = (num_rows as usize - 1)*2;
                if i % cycle == n || i % cycle == cycle - n {Some(c)} else {None}
            })
        );
    }
    iter.collect()
}

这给了我一个新的错误,说我需要声明一个类型:

error[E0282]: type annotations needed
 --> src/lib.rs:4:16
  |
2 |     let mut iter;
  |         -------- consider giving `iter` a type
3 |     for n in 0..num_rows as usize {
4 |         iter = iter.chain(
  |                ^^^^ cannot infer type
  |
  = note: type must be known at this point

所以,之后我尝试添加来自早期编译器错误的类型注释:

use core::str::Chars;
use core::iter::*;
let mut iter: Chain<FilterMap<Enumerate<Chars<'_>>, _>, FilterMap<Enumerate<Chars<'_>>, _>>;

这看起来很丑,但还是不行:

error[E0308]: mismatched types
  --> src/lib.rs:6:16
   |
6  |           iter = iter.chain(
   |  ________________^
7  | |             s.chars().enumerate().filter_map(|(i,c)| {
8  | |                 let cycle = (num_rows as usize - 1)*2;
9  | |                 if i % cycle == n || i % cycle == cycle - n {Some(c)} else {None}
10 | |             })
11 | |         );
   | |_________^ expected struct `std::iter::FilterMap`, found struct `std::iter::Chain`
   |
   = note: expected struct `std::iter::Chain<std::iter::FilterMap<std::iter::Enumerate<Chars<'_>>, _>, std::iter::FilterMap<std::iter::Enumerate<Chars<'_>>, _>>`
              found struct `std::iter::Chain<std::iter::Chain<std::iter::FilterMap<std::iter::Enumerate<Chars<'_>>, _>, std::iter::FilterMap<std::iter::Enumerate<Chars<'_>>, _>>, std::iter::FilterMap<std::iter::Enumerate<Chars<'_>>, [closure@src/lib.rs:7:46: 10:14]>>`

那么,我错过了什么?这怎么行?

您不能直接这样做,因为每次循环迭代都需要不同的类型:第一次 Chain<FilterMap, FilterMap>,第二次 Chain<Chain<FilterMap, FilterMap>, FilterMap>,然后 Chain<Chain<Chain<FilterMap, FilterMap>, FilterMap>, FilterMap>第三次,以此类推。

这个问题可以通过装箱迭代器来解决:

pub fn convert(s: String, num_rows: i32) -> String {
    let mut iter: Box<dyn Iterator<Item=char>> = Box::new (s.chars().enumerate().filter_map(|(i, c)| {
        if i % ((num_rows as usize - 1)*2) == 0 {Some(c)} else {None}}));
    for n in 1..num_rows as usize {
        iter = Box::new(iter.chain(
            s.chars().enumerate().filter_map(|(i,c)| {
                let cycle = (num_rows as usize - 1)*2;
                if i % cycle == n || i % cycle == cycle - n {Some(c)} else {None}
            }))
        );
    }
    iter.collect()
}

Playground

这给了你关于 n 被闭包借用的生命周期错误,通过添加 move:

很容易修复
pub fn convert(s: String, num_rows: i32) -> String {
    let mut iter: Box<dyn Iterator<Item=char>> = Box::new (s.chars().enumerate().filter_map(|(i, c)| {
        if i % ((num_rows as usize - 1)*2) == 0 {Some(c)} else {None}}));
    for n in 1..num_rows as usize {
        iter = Box::new(iter.chain(
            s.chars().enumerate().filter_map(move |(i,c)| {
                let cycle = (num_rows as usize - 1)*2;
                if i % cycle == n || i % cycle == cycle - n {Some(c)} else {None}
            }))
        );
    }
    iter.collect()
}

Playground