Rustでイテレータを積極的に使っていくメモ (逐次更新)

# 環境
Rust 1.6.0を前提に。
とはいえ、多少古くても問題ないはず。

## 前提
```rust
for i in x {
    foo(i);
}
```

というのは、

```rust
{
    let mut anonymous_iter = x.into_iter();
    while let Some(i) = anonymous_iter.next() {
        foo(i);
    }
}
```

と同じだ。

* * *

# 事例1: `Option<Vec<_>>` の中身のベクタについてループを回す
例として、「 `Option<Vec<String>>` が `Some` であれば、中のベクタの文字列を大文字にして表示する」ことを考える。

```rust:普通に書いたコード
let optvec = Some(vec!["foo".to_string(), 2.to_string(), "bar2baz".to_string()]);
if let Some(ref vec) = optvec {
    for i in vec {
        println!("{:?} => {:?}", i, i.to_uppercase());
    }
}
```

Optionの中身を `if let` で取り出す、まあ普通のコード。

iteratorを使ったコードはこうなる:

```rust:iteratorを使う
let optvec = Some(vec!["foo".to_string(), 2.to_string(), "bar2baz".to_string()]);
for i in optvec.iter().flat_map(|v| v.iter()) {
    println!("{:?} => {:?}", i, i.to_uppercase());
}
```

べつに `if let` や `match` を使ってもいいのだが、イテレータをうまく使うとネスト(というかインデント)を減らせるのでうれしい。

ちなみに、 `optvec` をmoveして良いのであれば、 `into_iter` を使う方が良い。オブジェクトをconsumeするような関数も呼べるためだ。

```rust
// 文字列をバイト列にして表示
for i in optvec.into_iter().flat_map(Vec::into_iter) {
    // iはmoveされてくるので、 `String::into_bytes(self)` が呼べる
    println!("{:?}", i.into_bytes());
} // まあこの場合mapを使った方がいいけどね
```

## 解説
### `Option::iter()`, `Option::into_iter()`
`Option<T>` 型が「0個か1個の値を持つコンテナ」と考えれば、 `Vec` や `HashMap` 等と同じようにイテレータを使ったりループを回せるのは自然だ。
そんなわけで(かどうかは知らないが)、 `Option<T>` はイテレータを作ることができる。

```rust
for i in Some(1) { // for i in Some(1).into_iter() と同じ
    println!("{}", i); // => 1
}
```

`if let` はあらゆる(?)型についてdestructureできるので強いが、 `Option` については `for in` を使うという選択肢もあるということだ。
わかりやすいかは別にして。

### `Vec::iter()`, `Vec::into_iter()`
その名の通り、ベクタの要素を列挙するイテレータを作るメンバ関数。

それは良いとして、なぜ `optvec.iter().flat_map(|v| v.iter())` で `|v| v.iter()` を使ったか。
ここでの `v` は `&Vec<_>` だが、実は `Vec<T>::iter` は存在せず、 `v.iter()` したとき [`Deref<Target=[T]>` というトレイトによる参照外し経由で `slice::iter` が呼ばれる](https://doc.rust-lang.org/std/vec/struct.Vec.html#deref-methods)ことで、イテレータを取得できるようになっているのである。
よって、メンバ関数一発で `Vec<_>` のイテレータを得ることはできないから、暗黙のderefを有効活用して `|v| v.iter()` と書くのが一番短くなるのである。

### `Iterator::flat_map()`
[std::iter::Iterator - Rust](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.flat_map) ←公式ドキュメントを読めばわかる。
簡単に言えば、
「イテレータに対して、『モノを受け取ってイテレータを返す関数』を受け取り、それぞれのイテレータを繋げて返す」、
つまり `Iter<T> -> (T -> Iter<U>) -> Iter<U>` という感じの関数だ。(伝われ！)

# 事例2: `Option<T>` の中身が条件を満たしていなかったら `None` にする
~~**追記 2017-11-15**: [Add `Option::filter()` according to RFC 2124 by LukasKalbertodt · Pull Request #45863 · rust-lang/rust](https://github.com/rust-lang/rust/pull/45863) という機能が入ったので、 Rust-1.22 からは、イテレータを使わずとも以下のようなコードで実現できます。~~

```rust:rust-1.27.0から
let optint = Some(3);
let positive = optint.filter(|&v| v >= 0);
println!("positive: {:?}", positive); // => 3
```

~~**追記2 2017-12-05**: [Tracking issue for Option::filter (feature `option_filter`) · Issue #45860 · rust-lang/rust](https://github.com/rust-lang/rust/issues/45860)
Unstable でした……~~

**追記3 2018-06-22**: [`Option::filter`](https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.filter) は rust 1.27 で安定化されました🎉

----

例として、「 `Option` の中身が負であれば `None` にし、そうでなければそのままにする」ことを考える。

```rust:愚直に書いたコード
let optint = Some(3);
let positive = if let Some(i) = optint {
    if i >= 0 {
        Some(i)
    } else {
        None
    }
} else {
    None
};
println!("positive: {:?}", positive); // => 3
```

`Some` なら｛非負なら `Some` 、それ以外なら `None` ｝、それ以外なら `None`
という感じ。ネストが重なって汚いうえ、`Some` を剥がしてまた包むという、なんとも美しくないコードだ。

```rust:ちょっとマシなコード
let optint = Some(3);
let positive = optint.and_then(|i| if i >= 0 { Some(i) } else { None });
println!("positive: {:?}", positive); // => 3
```

`Option::and_then()` を使って、一行にまとめた。
Cスタイルの三項演算子があればマシになるのだが、残念ながらRustでは `if` が式として使えるため、三項演算子は用意されていない。
(参考 ~~(さんこうだけに)~~: [Remove ternary operator · Issue #1698 · rust-lang/rust](https://github.com/rust-lang/rust/issues/1698))
ちなみに、ifの中括弧は省略できない。

イテレータを活用したコード:

```rust
let optint = Some(3);
let positive = optint.into_iter().find(|&v| v >= 0);
println!("positive: {:?}", positive); // => 3
```

短い。単純さは正義だ。
そして、「剥がして包む」という無駄に見える操作を書かずに済むようになった。

## 解説
### `Iterator::find()`
[std::iter::Iterator - Rust](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.find)
名前から想像される通り、「与えられた条件を最初に満たした要素を返す(`Some`)、もしひとつもなければ `None` 」という関数だ。
これを `Option` のイテレータに使えば、 `None` の場合は要素が無いということになるので `find` も `None` を返し、 `Some` で条件を満たさない場合も `None` を返し、 `Some` で条件を満たしていればそれを `Some` で返す、ということになる。

### `Iterator::and_then()`
[std::option::Option - Rust](https://doc.rust-lang.org/std/option/enum.Option.html#method.and_then)
Haskell風に書くと `Option<T> -> (T -> Option<U>) -> Option<U>` である。
というか、まさしくHaskellで言うところの `(>>=)` だ。
ちなみに、こいつは `Option` だけでなく、 `Result` にも用意されている ([std::result::Result - Rust](https://doc.rust-lang.org/std/result/enum.Result.html#method.and_then))。

# 事例3: `Option<T>` のイテレータで、最初の `None` の直前までをunwrapしたもののイテレータを得る。 `None` 以降は捨てる
要するに、 `take_while()` と `filter_map()` (或いは `unwrap()`)を組み合わせたようなことをしたい場合。

```rust:愚直に書いたコード
let vec = vec!["1", "2", "3", "lol", "5"];
for num in vec.into_iter().map(|v| v.parse::<i32>().ok()).take_while(|v| v.is_some()).map(|v| v.unwrap()) {
    print!("{},", num);
}
// 出力: 1,2,3,
```

```rust:ちょっと工夫してみたつもりのコード
let vec = vec!["1", "2", "3", "lol", "5"];
for num in vec.into_iter().map(|v| v.parse::<i32>().ok()).take_while(|v| v.is_some()).filter_map(|v| v) {
    print!("{},", num);
}
// 出力: 1,2,3,
```

美しくないなぁ。

このコードの根本的な問題は、 **一度 `is_some()` で型(variant)をチェックしておきながら、もう一度 `unwrap()` や `filter_map()` で全く同じ確認がされる** というところにある。
`unwrap()` だって、panicするか値を返すか選ぶために、ちゃんと型を確認しているのだ。
このオーバーヘッドをなくすためには、 `Some` であることの確認と、イテレータを切るのを、同時に行わなければならない。

そんな都合の良いメソッドが、実は用意されているのだ。
(思い付かない方は、手前味噌だが[Rustのイテレータの網羅的かつ大雑把な紹介 - Qiita](http://qiita.com/l1048576/items/34887794c146042aebf1)や、[std::iter::Iterator - Rust](https://doc.rust-lang.org/std/iter/trait.Iterator.html)を読んでみることをおすすめする。)

[`Iterator::scan()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.scan) である。
こいつは、[`Iterator::fold()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.fold)の途中経過を見えるようにしたようなものだが、イテレータの返す値として `Option` を返すことになっているので、これを利用する。

```rust:scan()を利用
let vec = vec!["1", "2", "3", "lol", "5"];
for num in vec.into_iter().scan((), |_, v| v.parse::<i32>().ok()) {
    print!("{},", num);
}
// 出力: 1,2,3,
```

## 解説
だいたい見ればわかるが。
`Iterator::scan()` の第1引数(この使い方では `()`)は、状態である。
今回は状態は不要なので `()` を渡そう。たぶん最適化がきく。(本当かな？)

第2引数は `&mut State -> T -> Option<U>` のような関数だ。
`&mut State` は状態。今回は使わないので `_` で受ける。
`T` は元のイテレータの要素の型、ここでは文字列(`&str`)だ。これを `v` で受ける。
関数の戻り値 `Option<U>` の `U` は、新しいイテレータの要素の型である。
今回はパース後の `i32` が欲しいので、 `Option<i32>` を返す。
ただし `parse()` は `Result` を返すので、 `Result::ok()` で `Option` に変換する。

## fold との組み合わせ
もし `Ok(_)` の値を `fold()` へ流そうとしているのであれば、 `scan()` を経由せず、 rust 1.27 で安定化された [`Iterator::try_fold()`](https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.try_fold) を直接使うべきである。

# 事例3: `write!()` 等でコンマ区切りのリストを表示する(ただしケツカンマは認めない)

多少コードは変化するが、基本的に `io::Write` でも `fmt::Formatter` でも使える。

```rust
list.iter().try_fold("", |sep, arg| {
    write!(f, "{}{}", sep, arg).map(|_| ", ")
})?;
```

実際それっぽい感じで使うと、[こんな感じ (playground)](https://play.rust-lang.org/?gist=7267a5a6d4060edd852dca0bdab4faa4&version=beta&mode=debug) になる。

或いは、以下のように汎用的な関数を作ることもできる。

```rust
use std::fmt;
use std::io;

fn write_with_sep<W, T, I>(mut w: W, iter: I, sep: &str) -> io::Result<()>
where
    W: io::Write,
    T: fmt::Display,
    I: IntoIterator<Item = T>,
{
    iter.into_iter().try_fold("", |s, item| {
        w.write_fmt(format_args!("{}{}", s, item))?;
        Ok(sep)
    }).map(|_| ())
}

fn main() {
    let src = vec![1, 2, 4, 8, 16];
    write_with_sep(io::stdout(), src, " => ").expect("Write failed");
}
```
[(playground)](https://play.rust-lang.org/?gist=6af75929294846781a13e85c09312b92&version=beta&mode=debug)

## 考え方

仕掛けとしては単純で、 `try_fold` は基本的に `fold` と同じで「前の要素を処理した結果を次の要素の処理へ渡す」という役割を持っている。
そこで、これを「処理の結果」である出力成功/失敗の伝達と、「区切りが必要か否か」の伝達の両方に同時に使ってやろうという発想である。

```rust:フラグを使った素朴な実装
let mut needs_leading_comma = false;
for item in iter {
    if needs_leading_comma {
        w.write_fmt(format_args!("{}", sep))?;
    }
    write!(w, "{}", item)?;
    needs_leading_comma = true;
}
Ok(())
```

if で「何も表示しない」コードと分岐する代わりに、「空文字列を表示する」コードにすることで分岐をまとめることができる。

```rust:ifを消した
let mut leading_sep = "";
for item in iter {
    write!(w, "{}{}", leading_sep, item)?;
    leading_sep = sep;
}
Ok(())
```

ここで、ループ中で伝達されるべき「状態」は `leading_sep` 、初期値は `""` である。
`try_fold` で使うために、 `leading_sep` に `sep` を代入する代わりに `Ok(sep)` を返す。

```rust
iter.into_iter().try_fold("", |leading_sep, item| {
    write!(w, "{}{}", leading_sep, item)?;
    Ok(sep)
})?;
Ok(())
```

はい。
お好みで `.map(|_| ())` もどうぞ。


## 事例4: `take_while` で読み捨てられる最後の値を拾う
```rust
let a = [1, 2, 3, 4];
let mut iter = a.into_iter();

let result: Vec<i32> = iter
    .by_ref()
    .take_while(|n| **n != 3)
    .cloned()
    .collect();

assert_eq!(result, &[1, 2]);

let result: Vec<i32> = iter.cloned().collect();

assert_eq!(result, &[4]);
```

[playground](https://play.rust-lang.org/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0Alet%20a%20%3D%20%5B1%2C%202%2C%203%2C%204%5D%3B%0Alet%20mut%20iter%20%3D%20a.into_iter()%3B%0A%0Alet%20result%3A%20Vec%3Ci32%3E%20%3D%20iter.by_ref()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.take_while(%7Cn%7C%20**n%20!%3D%203)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.cloned()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.collect()%3B%0A%0Aassert_eq!(result%2C%20%26%5B1%2C%202%5D)%3B%0A%0Alet%20result%3A%20Vec%3Ci32%3E%20%3D%20iter.cloned().collect()%3B%0A%0Aassert_eq!(result%2C%20%26%5B4%5D)%3B%0A%7D), [公式リファレンス](https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.take_while) の例より

この例からわかるように、3は読み捨てられてしまう。
これを拾いたい場合にどうするか。

[`inspect`](https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.inspect) を使う。

```rust
let a = [1, 2, 3, 4];
let mut iter = a.into_iter();

let mut last_read = None; // <- Keep the last value
let result: Vec<i32> = iter
    .by_ref()
    .inspect(|n| last_read = Some(**n)) // <- Store the last value
    .take_while(|n| **n != 3)
    .cloned()
    .collect();

assert_eq!(result, &[1, 2]);
assert_eq!(last_loaded, Some(3)); // Here you are

let result: Vec<i32> = iter.cloned().collect();

assert_eq!(result, &[4]);
```

[playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=678ba394edff23af23fb8328bb9dfa4f)

### 解説

本来 [`inspect`](https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.inspect) は、その名の通り、イテレータを流れる要素を検査する (特にデバッグ目的などでログを吐く) ために使われる。
リファレンスのサンプルコードでもそういった用途で使われている。

この関数は「要素の参照を受け取って `()` を返す」ものであり、副作用を前提に作られているため、実際には表示以外でも、値をイテレータに流すようなことでなければほぼ何でもできる。
そこで、これをログ出力ではなく「流れてきた値を複製して、イテレータ外に用意された変数に保存する」という目的に利用しているのが、上のコードである。

勿論無駄なコピーは発生してしまうが、それが気になるようであれば、最初からもっと効率の良いアダプタを自分で書くなり crate を探すなりループを使うなりするべきである。


* * *

# まとめ

- イテレータは `for` ループで使える
- `Option` はイテレータを作れる
- `Iterator` の関数を活用すると、列挙されるものの中身を弄れる
  * ので、ネストとかを減らせることがある
  * 「はがす」「はがさず変化させる」のような操作は、どうにかしてイテレータを使えると考えるべし
- 以下のページは一度全体を読んでおくと様々な場面で活用できるので、全部の関数を眺めておくと、いざというとき「こんな関数あったよな……」と思い出せる
  * [std::iter::Iterator - Rust](https://doc.rust-lang.org/std/iter/trait.Iterator.html)
  * [std::option::Option - Rust](https://doc.rust-lang.org/std/option/enum.Option.html)
    * [std::result::Result - Rust](https://doc.rust-lang.org/std/result/enum.Result.html)

何か良い例や書き方、「こんなクソな書き方しねーよ！」等、ご意見があれば是非教えてください。