67304

[code]

    // Code 1
    fn main(){
        for vect in vec![0,1,2,3,4,5,6,7,8,9].iter(){
            println!("{}",vect);
        }
    }
    
[/code]

例えば上記のコードを実行すると、縦に整列した10個の数字を得ることができます。同時に、

[code]

    // Code 2
    fn main(){
        for vect in vec![0,1,2,3,4,5,6,7,8,9]{
            println!("{}",vect);
        }
    }
    
[/code]

でも同じ結果を得ることができます。ここで本題ですが、`Code 1`と`Code 2`では何が異なるのでしょうか？  
またRustにおけるイテレータの存在意義とは？

自分の古巣のRubyにもイテレーターはありましたが、全て`for`で解決していたため、結局何のために（目標のデータを反復することには間違いない）用意されているのか疑問に思っていました。参考文献を読んでも`イテレーターの存在意義を前もって知っている事`を前提に書かれおり非常に悩んでいます。


CC BY-SA 4.0
2020-06-04T20:10:00.240
67296
2020-06-05T00:50:35.517
30493
question
rust
Rustに於いての「.iter()」メソッド等イテレータの存在意義とは


こんにちは。ちょっと長くなりますが、お付き合い下さい。

# Code 1とCode 2の違い

まずは本題にお答えすると、Code 1とCode2では所有権の扱いが異なります。後程説明しますが、Code 1もCode
2も（内部的に）イテレータを使ったコードになっているので、イテレータを使うかどうかという違いはないです。

Code 1では `vec!` で作られた値を参照しており、 Code 2では `vec!` で作られた値を消費しています。これは1. `vect` の型が
`&i32` か `i32` か、 2. `for` 式文のあとでベクトルが使えるかどうか、で違いが表われます。少しコードを書き換えて試してみましょう。

[code]

    // Code 1
    fn main(){
        // 一旦変数を束縛しておく
        let vec = vec![0,1,2,3,4,5,6,7,8,9];
        for vect in vec.iter() {
            // vecを参照しているので、要素も参照になる
            // vectは&i32
            let vect: &i32 = vect;
            println!("{}",vect);
        }
        // forのあともvecを使える
        println!("{:?}", vec);
    }
    
[/code]

[code]

    // Code 2
    fn main(){
        // 一旦変数を束縛しておく
        let vec = vec![0,1,2,3,4,5,6,7,8,9];
        for vect in vec {
            // vecを消費しているので、要素をそのまま取り出せる
            // vectはi32
            let vect: i32 = vect;
            println!("{}",vect);
        }
        // forのあとvecを使おうとすると所有権エラー
        // println!("{:?}", vec);
    
        // error[E0382]: borrow of moved value: `vec`
        //  --> iter.rs:8:22
        //   |
        // 2 |     let vec = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        //   |         --- move occurs because `vec` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
        // 3 |     for vect in vec {
        //   |                 ---
        //   |                 |
        //   |                 value moved here
        //   |                 help: consider borrowing to avoid moving into the for loop: `&vec`
        // ...
        // 8 |     println!("{:?}", vec);
        //   |                      ^^^ value borrowed here after move
        // 
        // error: aborting due to previous error
        // 
        // For more information about this error, try `rustc --explain E0382`
    }
    
[/code]

# イテレータの存在意義

## イテレータと `for` の関係

次にイテレータの存在意義ですが、一番分かりやすいのは `for` 式文のためです。`for` とイテレータは独立したものではなく、 `for`
はイテレータを便利に使うための構文なのです。

Rustで `for` を書いたときは、コンパイラが裏で `while let` という構文とイテレータを使った表現に書き換えています。

[code]

    // for
    for e in v {
        // do something
    }
    
[/code]

[code]

    // 上の式はこう展開される
    let mut iter = v.into_iter();
    while let Some(e) = iter.next() {
        // do something
    }
    
[/code]

Rubyも同様に `for` 文は `each` で書き換えられます（参考: [制御構造 (Ruby 2.7.0
リファレンスマニュアル)](https://docs.ruby-
lang.org/ja/latest/doc/spec=2fcontrol.html#for)）

RubyでもRustでも配列や範囲(`start..end`)など、違うオブジェクトを `for` で扱えるのはイテレータで抽象化しているからなのです。

## その他の存在意義

イテレータの他の存在意義は

  1. 「くりかえせるもの」という概念を抽象化する
  2. `for` でやりがちな処理をメソッドとして共通化できる
  3. （Rustにおいては）パフォーマンス上のメリットもある

などが挙げられます。3は少し込み入るので1, 2についてだけ触れます。

### 1.「くりかえせるもの」という概念を抽象化するについて

Rubyだとダックタイピングがあるので意義が薄いですが、Rustだと概念の抽象化は必須です。例えばベクトルを拡張する [`extend`
メソッド](https://doc.rust-lang.org/std/vec/struct.Vec.html#impl-
Extend%3CT%3E)はこういう型シグネチャをしています。

[code]

    fn extend<I>(&mut self, iter: I) where
        I: IntoIterator<Item = T>,
    
[/code]

イテレート可能なもの（正確には `IntoIterator`
を実装している型ですが）ならなんでも引数にとれます。このおかげで、次のようにベクトルやスライス、範囲などさまざまなものを引数にとれます。

[code]

    let mut vec = vec![1];
    // Vec<T> を渡せる
    vec.extend(vec![2, 3]);
    // &[T] を渡せる
    vec.extend([4, 5, 6]);
    // Range<T> を渡せる
    vec.extend(7..10);
    
[/code]

このように、「くりかえせるもの」を値として扱いたいときに有用です。

### 2.`for` でやりがちな処理をメソッドとして共通化できるについて

そのままですが、よくある処理をメソッドとして共通化できると便利です。例えば「最初の5要素の和をとる」処理はイテレータを使えばRustでこう書けます。

[code]

    vec.into_iter().take(5).sum()
    
[/code]

同じことは `for` でも書けますが、
5つ数えたり合計値を収める変数を用意したり、ちょっと手間がかかりますよね？それらをメソッドにまとめることで手間を節約できます。あるいは、
[`zip`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.zip)のように
`for` では少し書きづらいような処理もメソッドにできます。

# まとめ

以上で `vec![]` と `vec![].iter()` の違いと、イテレータの存在意義が伝わったでしょうか。蛇足になりますが、下に余談が2つ続きます。

# 余談

## 余談1 `for vect in vec![..].iter() { /* ... */}` について

先程説明したとおり、この式は以下のように展開されます。

[code]

    let mut vec = vec![..].iter().into_iter();
    while let Some(vect) = vec.next() {
        // ...
    }
    
[/code]

`vec![..].iter().into_iter()` という式が出てきましたね。イテレータを2回とっているようで無駄に見えるのは置いておきましょう。  
注目するのは返り値です。この式は `std::slice::Iter` を返します。ところで、 `Vec` から `std::slice::Iter`
を得るのは実は別のやり方があります。`(&vec![..]).into_iter()` でも同じものが出てくるのです。  
つまり、 `vec![..].iter()` == `vec![..].iter().into_iter()` ==
`(&vec![..]).into_iter()` です。`into_iter` は `for`
が勝手につけてくれるので、結局以下の2つの式は同等ということになります。

[code]

    // .iter() を呼ぶやりかた
    for vect in vec![..].iter() {
        // ...
    }
    
[/code]

[code]

    // &をつけるやりかた
    for vect in &vec![..] {
        // ...
    }
    
[/code]

Rustではイテレータを意識しない `&vec![..]` の方が好ましい書き方とされています。See
[explicit_iter_loop](https://rust-lang.github.io/rust-
clippy/stable/index.html#explicit_iter_loop)

## 余談2 内部イテレータと外部イテレータ

RubyのイテレータとRustのイテレータは実は種類が違います。Rubyのものは内部イテレータ、Rustのものは外部イテレータと呼ばれます。

Rubyのものは `it.each {|e| ... }`
のように、処理をメソッドに渡してしまうスタイルです。これはイテレータ自身が繰り返し処理を担当します。

Rustのものは `while let Some(e) = it.next() { ... }` のように、他の制御構造と組合せて使うスタイルです。

今回の質問にこれらの違いが関係することはないのですが、両者をないまぜにしてイテレータのことを考えていると混乱しかねないので一言補足しました。


CC BY-SA 4.0
2020-06-05T00:50:35.517
67304
2020-06-05T00:50:35.517
22816
67296
answer