Rustでイテレータメソッドを使おう

こちらLTにて発表させていただきました。
https://uniquevision.connpass.com/event/191020/

## 自己紹介

- ユニークビジョン株式会社 1年目
- プログラミングを学び始めたのは大学生から
- Rustはだいたいその1年後からずっと触っています

## イテレータとは

> 配列やそれに類似する集合的データ構造（コレクションあるいはコンテナ）の各要素に対する繰り返し処理の抽象化である。
> （Wikipediaより）

---

## イテレータとは

> 配列やそれに類似する集合的データ構造（コレクションあるいはコンテナ）の各要素に対する繰り返し処理の抽象化である。
> （Wikipediaより）

要するに、「いま何番目の要素を見ているか」を気にすることなく順番に各要素を用いた処理を行う方法のことを指しています。

---

## 配列へのアクセス

例えばC言語やJavaなどにおいて、配列に対してfor文を用いて順番に添え字でアクセスすると以下のようになります。

```java
int[] list = new int[1, 2, 3]; // Javaの場合
for (int i = 0; i < list.length; i++) {
  println(list[i]); // => 1 2 3
}
```

これでは単に繰り返し各要素を用いたいだけなのに、変数`i`の状態まで気にしなくてはなりません。
そこで次のような構文が用意されていたりします。

```java
int[] list = new int[1, 2, 3];
forEach (int v : list) {
  println(v); // => 1 2 3
}
```

添え字は用いておらず、各要素が一度だけ順番に渡されます。

---

## イテレータとは

改めて...

イテレータとは、for文（for-each文、拡張for文）のように「一連の要素にある処理を適用させる方法」の一つです。

---

## イテレータの特徴

配列やそれに類似する集合的データ構造に対し、「一連の要素を順番に適用させたい（引数に取る）**処理**」を渡すとその副作用を得られるメソッドがたくさん用意されている。

- 要素の可変参照を受け取って変化させる
- 特定の要素だけに絞り込みたい
- 全く別の新しい構造体を作成する

などなど...

---

## Rustにおけるイテレータの実装方法

Rustには`Iterator`トレイトというものが用意されています。

これを実装するのに必要なのは、`next`メソッドの処理を記述することだけです。あとはその`next`メソッドを用いた様々なメソッドが実装されます。

```rust:Iteratorトレイトの実装
struct TenCounter {
  count: usize,
}

impl TenCounter {
  fn new() -> Self {
    Counter { count: 0 }
  }
}

impl Iterator for TenCounter {
  type Item = usize;

  fn next(&mut self) -> Option<Self::Item> {
    if self.count < 10 {
      self.count += 1;
      Some(self.count)
    } else {
      None
    }
  }
}

// main
let mut counter = TenConter::new();
assert_eq!(counter.next(), Some(1));
assert_eq!(counter.next(), Some(2));
...
assert_eq!(counter.next(), Some(10));
assert_eq!(counter.next(), None);
```

---

## 便利なイテレータメソッドの紹介

### `map`

各要素をクロージャに渡し、その返り値のイテレータを返す

```rust
let iter = (1..=3).iter().map(|x|x * 2);
assert_eq!(Some(&2), iter.next());
assert_eq!(Some(&4), iter.next());
assert_eq!(Some(&6), iter.next());
```

### `any`, `all`

- `any`：ある要素に対しクロージャがtrueを返したらtrue
- `all`：すべての要素に対しクロージャがtrueを返したらtrue

```rust
let chars = "Rust".chars();
assert!( chars.any(|c|c.is_lowercase()));
assert!(!chars.all(|c|c.is_lowercase()));
```

### `enumerate`

- イテレータの各要素を、`(インデックス, 要素)`というタプルに置き換えたイテレータを返す

```rust
assert_eq!(
  Some(1),
  "foo".chars().enumerate().find(|&(i, c)|c == 'o').map(|it|it.0)
);

// ちなみにこっちでも同じ
assert_eq!(
  Some(1),
  "foo".chars().position(|&c|c == 'o')
);
```

### `inspect`

- メソッドチェーンしすぎると途中の状態がわかりづらくなる
- そういった場合に、途中の要素に対して何か操作するわけではなく、単に参照を受け取って状態を確認するなどで用いる
- 主にデバック用

```rust
let list: Vec<i32> = (1..=5)
    .map(|x|x + 2)
    .filter(|x|x >= 5)
    .inspect(|x|println!("{}", x))
    .map(|x|x * 3)
    .collect();
```

### `skip`, `skip_while`

与えた回数、もしくはクロージャがtrueを返す間は要素をスキップ（切り捨て）していく

```rust:skip
let args: Vec<String> = std::env::args()
    .skip(1) // プログラム名をスキップ
    .collect();
```

```rust:skip_while
let list_over_5: Vec<i32> = (1..=10).skip_while(|x|**x < 5).collect();
assert_eq!(iter.next(), Some(5));
assert_eq!(iter.next(), Some(6));
...
assert_eq!(iter.next(), Some(10));
assert_eq!(iter.next(), None);
```

### `filter_map`

- Optionを返すクロージャを渡し、クロージャがSomeを返したものの**中身**のイテレータを作成する

```rust
let list = ["1", "2", "lol"];
let mut iter = a.iter().filter_map(|s| s.parse().ok()); // ok() : Result::Ok(T)をOption::Some(T)に変換する
assert_eq!(iter.next(), Some(1));
assert_eq!(iter.next(), Some(2));
assert_eq!(iter.next(), None);
```

### `flat_map`

- IntoIteratorトレイトを実装している型を返すクロージャを引数にする
- 要素をそれぞれイテレータにしつなげていったイテレータを返す。

```rust:公式の例
let words = ["alpha", "beta", "gamma"];
let merged: String = words.iter()
    .flat_map(|s| s.chars())
    .collect();
assert_eq!(merged, "alphabetagamma");
```

### `filter_map`と`flat_map`の比較

```rust:filter_mapを使う
let list = ["1", "2", "lol"];
let mut iter = a.iter().filter_map(|s| s.parse().ok());
assert_eq!(iter.next(), Some(1));
assert_eq!(iter.next(), Some(2));
assert_eq!(iter.next(), None);
```

```rust:flat_mapを使う
let a = ["1", "2", "lol"];
let mut iter = a.iter().flat_map(|s| s.parse()); // `.ok()` 要らず
assert_eq!(iter.next(), Some(1));
assert_eq!(iter.next(), Some(2));
assert_eq!(iter.next(), None);
```

---

# Option, Result

- 同じようにIteratorトレイトを実装している
  - 要素1のイテレータになる
- 加えて、それぞれの型に実装されているメソッドもイテレータのような挙動をするものが多い

例）

```rust
let maybe_i32 = Option::Some(10);
assert_eq!(
  Some(10),
  maybe_i32.filter(|x|*x > 5)
)
```

---

## イテレータを用いる際の注意点

- 自身を消費するメソッドがけっこうある
  - 例えば`count()`や`max()`など
- 参照のイテレータなのか、生の要素を持っているイテレータなのか
  - `iter()`と`into_iter()`

---

## Rustは頻繁にイテレータが用いられる

- stdモジュールで実装されているメソッドの返り値が、Iteratorトレイトやそれに類似したトレイトを実装していることが多い
- 複数のデータを扱うような場面ではおおよそ同じような処理で対応可能
- 上手く扱えば、記述量や可読性を上げることができる

---

## 参考にさせていただいた記事

- [Rustのイテレータの網羅的かつ大雑把な紹介](https://qiita.com/lo48576/items/34887794c146042aebf1)
- [Rustでイテレータを積極的に使っていくメモ (逐次更新)](https://qiita.com/lo48576/items/ccef72649883af343f84)