Rustのイテレータについて

## はじめに

Rustにはイテレータというコレクション型に対する便利な仕組みがあります。
ですが実際に使ってみると型が値か参照かで結構戸惑います。
またイテレータにも何種類かあり、ややこしいので調べたことをまとめました。

## イテレータとは

イテレータとは配列やベクタ等の複数の要素を持つデータ型に対して
先頭から順番に各要素にアクセスできる仕組みのことです。

イテレータを使うことで添え字を使わずに要素にアクセスしたり、複雑な処理を簡潔に書くことができます。

## iter

イテレータは`iter`で取得できます。
`iter`が返すのは各要素への**参照**です。

```rust
let nums: Vec<i32> = vec![0, 1, 2, 3, 4];
for x in nums.iter() { //変数xの型は&i32
    println!("{}", x);
}
```

以下ではよく使う関数をいくつか紹介します。

### for_each

各要素に対して処理を適用させたい場合は`for_each`も使えます。
引数にクロージャ(無名関数)を渡します。
上記のコードは`for_each`で置き換えると下記の様になります。

```rust
nums.iter().for_each(|x: &i32| println!("{}", x));
```

### sum

`sum`でイテレータ内の数値の合計を求められます。

```rust
let nums: Vec<i32> = vec![0, 1, 2, 3, 4];
// 10
let sum: i32 = nums.iter().sum();
```

### fold

`fold`でイテレータ内の要素を元に1つの返り値を得ることができます。
第1引数が初期値、第2引数が各要素に適用させるクロージャです。
クロージャの第1引数は各要素に適用される毎に更新されます。

下記のコードではイテレータ内の数値の総乗を求めています。

```rust
let nums = vec![1, 2, 3, 4, 5];
// 120
let total: i32 = nums.iter().fold(1, |total: i32, x: &i32| total * x); 
```

### map

`map`を使うとイテレータの各要素に対して処理を適用させて、新しいイテレータを生成することができます。
下記のコードでは数値文字列のイテレータから数値のイテレータを生成して総和を求めています。

```rust
let str_nums: Vec<&str> = vec!["1", "3", "5", "7", "9"];
// 25
let sum: i32 = str_nums.iter().map(|x: &&str| x.parse::<i32>().unwrap()).sum();
```

また`collect`でイテレータをベクタに変換できます。

```rust
let nums: Vec<i32> = vec![0, 1, 2, 3, 4];
// [10, 11, 12, 13, 14]
let nums2: Vec<i32> = nums.iter().map(|x: &i32| x + 10).collect();
```

### filter

`filter`で条件に一致する要素を抽出できますが、いくつか注意点があります。
クロージャに渡される要素の型は**参照への参照**なので`*`を付けないと値を取得することできません。
また、`filter`が返すのは一致した要素への**参照**のイテレータです。

```rust
let nums: Vec<i32> = vec![0, 1, 2, 3, 4];
let nums2: Vec<&i32> = nums.iter().filter(|x: &&i32| *x % 2 == 0).collect();
```

抽出した結果を値のベクタとしたい場合は、`cloned`でコピーを作成する必要があります。

```rust
let nums: Vec<i32> = vec![0, 1, 2, 3, 4];
let nums2: Vec<i32> = nums.iter().cloned().filter(|x: &&i32| *x % 2 == 0).collect();
```

## 参照の分配

クロージャの引数に`&`を付けると参照外しが行われた状態で引数に渡されます。
これを**参照の分配**といいます。

```rust
let nums: Vec<i32> = vec![0, 1, 2, 3, 4];
// クロージャの引数xの型は&&i32
let sum: i32 = nums.iter().filter(|x| *x % 2 == 0).sum();
// クロージャの引数xの型は&i32
let sum: i32 = nums.iter().filter(|&x| x % 2 == 0).sum();
// クロージャの引数xの型はi32
let sum: i32 = nums.iter().filter(|&&x| x % 2 == 0).sum();
```

参照の分配を行うと型注釈は常に`&_`になります。
なので下記のコードはコンパイルエラーになります。

```rust
let sum: i32 = nums.iter().filter(|&x: &i32| x % 2 == 0).sum();
```

また、参照の分配で引数の型を値にするとコピーが渡されます。
そのためCopyトレイトが実装されていない型だとコンパイルエラーになります。

```rust
let strings: Vec<String> = vec!["A".to_string(), "BC".to_string(), "DEF".to_string()];
// String型はCopyトレイトが実装されていないのでコンパイルエラー
let filtered: Vec<&String> = strings.iter().filter(|&&s| s.len() == 2).collect();
```

この場合、引数の型を参照にするとコピーが発生しないのでコンパイルが通ります。

```rust
let filtered: Vec<&String> = strings.iter().filter(|&s| s.len() == 2).collect();
```

## iter_mut

イテレータで各要素の値を変更をしたい場合は`iter_mut`を呼び出します。
`iter_mut`は各要素への**可変参照**を返します。

```rust
let mut nums: Vec<i32> = vec![0, 1, 2, 3, 4];
for x in nums.iter_mut() { // 変数xの型は&mut i32
    *x *= 2;
}
println!("{:?}", nums); // [0, 2, 4, 6, 8]
```

上記のコードを`for_each`で置き換えると下記の様になります。

```rust
let mut nums: Vec<i32> = vec![0, 1, 2, 3, 4];
nums.iter_mut().for_each(|x: &mut i32| *x *= 2);
println!("{:?}", nums); // [0, 2, 4, 6, 8]
```

## 可変参照の分配

可変参照においても参照の分配は可能ですが、意図した動作を行いません。
下記のコードではnums内の要素は変化していません。
これはクロージャの引数に要素のコピーが渡されるためです。

```rust
let mut nums: Vec<i32> = vec![0, 1, 2, 3, 4];
nums.iter_mut().for_each(|&mut mut x| x *= 2);
println!("{:?}", nums); // [0, 1, 2, 3, 4]
```

## into_iter

`iter`と`iter_mut`は所有権の移動は発生しませんが、`into_iter`は所有権が移動します。
`into_iter`の返り値は参照ではなく値になります。

```rust
let nums = vec![0, 1, 2, 3, 4];
for x in nums.into_iter() { // 変数xの型はi32
    println!("{}", x);
}
println!("{:?}", nums);  // 所有権が移動したのでnumsは使えない
```

クロージャの引数の型は値か参照になります。

```rust
let nums = vec![0, 1, 2, 3, 4];
let nums2: Vec<i32> = nums
    .into_iter()
    .map(|x: i32| x + 10)         // 引数の型は値
    .filter(|x: &i32| x % 2 == 1) // 引数の型は参照
    .collect();
println!("{:?}", nums2); // [11, 13]
```

クロージャの引数に`mut`を付けると各要素を可変な変数として扱うことができます。

```rust
let strings: Vec<String> = vec!["A".to_string(), "B".to_string(), "C".to_string()];
strings.into_iter().for_each(|mut s| {
    s += "_Suffix";
    println!("{}", s);
});
```

## まとめ

### イテレータ

| 関数名         | 可変か不変か       | イテレータの返り値      | 所有権   |
| ----------- | ------------ | -------------- | ----- |
| `iter`      | 不変           | `&T`(参照)       | 移動しない |
| `iter_mut`  | 可変           | `&mut T`(可変参照) | 移動しない |
| `into_iter` | 不変(`mut`で可変) | `T`(値)         | 移動する  |

### 参照の分配

変数の先頭に`&`を付けると、参照外しをしてから変数に代入される。
参照外しで型が値になると参照先変数のコピーが代入される。

```rust
let x: i32 = 5;
let y = &x;  // 変数yの型は&i32 変数xへの参照
let &z = &x; // 参照の分配により変数zの型はi32 変数xのコピーが代入される
```

## 参考文献

https://doc.rust-jp.rs/book-ja/ch13-02-iterators.html

https://doc.rust-lang.org/std/iter/trait.Iterator.html

https://doc.rust-jp.rs/book-ja/ch18-03-pattern-syntax.html#%E5%8F%82%E7%85%A7%E3%82%92%E5%88%86%E9%85%8D%E3%81%99%E3%82%8B