Chapter 21

イテレータ

mebiusbox
mebiusbox
2023.03.16に更新

📌 イテレータ

イテレータ は連続したオブジェクトを順番に取り扱うための機能を提供するオブジェクトです.配列やスライス,後で解説する コレクション でよく使います.イテレータは Iterator トレイトのインスタンスです:

pub trait Iterator {
    type Item;
    fn next(&mut self) -> Option<Self::Item>;
    
    // methods with default implementations elided
}

ここで, type Item関連型 と呼ばれるもので,インスタンスはこの Item 型を定義しなければなりません.

イテレータには多くの便利なメソッドが定義されています.いくつか紹介します.

🔹 zipメソッド

まずは zipメソッドです.これは別のイテレータを受け取って合成し,新しいイテレータを返します.要素はタプルになります.このようなイテレータから別のイテレータを作るメソッドは アダプタ と呼ばれています.

let a1 = [1, 2, 3];
let a2 = [4, 5, 6];
let mut iter = a1.iter().zip(a2.iter());

🔹 mapメソッド

mapメソッドは各要素に関数を適用します:

let a = [1, 2, 3];
let mut iter = a.iter().map(|x| 2 * x);

🔹 filterメソッド

filterメソッドは各要素に対して関数を適用し, true を返した要素だけを取り出します:

let a = [0i32, 1, 2];
let mut iter = a.iter().filter(|x| x.is_positive());

🔹 foldメソッド

foldメソッドは状態を持ち,各要素に対して関数を適用して状態を更新し,その状態を返します:

let a = [1, 2, 3];
// the sum of all of the elements of the array
let sum = a.iter().fold(0, |acc, x| acc + x);

🔹 collectメソッド

collectメソッドはイテレータの全要素をコレクションに変換します:

let a = [1, 2, 3];
let doubled: Vec<i32> = a.iter()
                         .map(|&x| x * 2)
                         .collect();

🔹 enumerateメソッド

enumerateメソッドはインデックスと各要素のペアをタプルにします:

let a = ['a', 'b', 'c'];
let mut iter = a.iter().enumerate();
// (0, &'a'), (1, &'b'), (2, &'c')

🔹 for_eachメソッド、inspectメソッド

for_eachメソッドは要素に関数を適用しますが,その関数は戻り値を返しません.また, for_eachメソッドはイテレータを返しません.それに対して, inspectメソッドはイテレータを返します. mapメソッドではprintln!マクロといったIO出力などの副作用が使えないので代わりにinspectメソッドを使います:

let a = [1, 4, 2, 3];
let sum = a.iter()
    .cloned()
    .inspect(|x| println!("about to filter: {}", x))
    .fold(0, |sum, i| sum + i);
println!("{}", sum);

🔹 イテレータを返すメソッド

コレクションなどはイテレータを返すiterメソッド, iter_mutメソッド, into_iterメソッドがあります.それぞれ,引数に &self, &mut self, self を受け取ります.