for循环的元素遍历本质上就是调用了对应的迭代器方法,返回一个迭代器,然后不断的进行迭代访问所有的元素。

for item in collection {
    // body
}

// 等于下面这段代码

let mut iter = collection.into_iter();
loop {
    let item: Thing = match iter.next() {
        Some(item) => item,
        None => break,
    };
    // body
}

迭代器的每一个元素都是另外一个迭代器,通过flat_map可以将所有内部的迭代器都展开,形成一个大的迭代器。

let data = vec!["abc", "def"];
// 通过flat_map,将内部的&str又展开成一个新的迭代器了,最终将所有的迭代器组成一个	
let c = data.into_iter().flat_map(|e| e.chars().into_iter());
for i in c {
    println!("item: {}", i)
}
// Output: 
item: a
item: b
item: c
item: d
item: e
item: f

如果迭代器内部的元素是一个Result类型,Result内部的元素是可迭代的,这个时候,如何处理呢?


let data = vec!["abc", "def"];
let c = data
    .into_iter()
    .map(|res| Ok(res))
    .flat_map(|res| match res {
        Ok(e) => e.chars().into_iter().map(Ok),
        Err(err) => std::iter::once(err),
    });

|
60 |           .flat_map(|res| match res {
   |  _________________________-
61 | |             Ok(e) => e.chars().into_iter().map(Ok),
   | |                      ----------------------------- this is found to be of type `Map<Chars<'_>, fn(char) -> Result<char, _> {Result::<char, _>::Ok}>`
62 | |             Err(err) => std::iter::once(err),
   | |                         ^^^^^^^^^^^^^^^^^^^^ expected struct `Map`, found struct `std::iter::Once`
63 | |         });
   | |_________- `match` arms have incompatible types
   |

flat_map要求内部返回的是一个迭代器,我们展开Result类型后,通过into_iter获取迭代器,为了让最终迭代器返回的元素可以区分是Err和真实的内容,因此我们返回的迭代器元素也是一个Result类型,因为是Result类型,因此可能有Err的存在,当出现Err的时候,我们也需要返回的一个迭代器。这里通过std::iter:once,将Err变成了迭代器,但是match的两个arm返回的类型不一样,导致编译报错,为了解决上面这个问题,我们引入了either这个crate,这个crate可以存放不同类型的元素。

use either::Either::{Left, Right};
let data = vec!["abc", "def"];
let c = data
    .into_iter()
    .map(|res| Ok(res))
    .flat_map(|res: Result<&str, std::io::Error>| match res {
        Ok(e) => Left(e.chars().into_iter().map(Ok)),
        Err(err) => Right(std::iter::once(Err(err))),
    });

通过Either的Left,Right来统一了match arm两边的类型,统一成Either,这个类型本身也实现了Iterator trait,因此符合flat_map的返回的类型的要求。