Rust における反復子の実装

Beginner

This tutorial is from open-source community. Access the source code

はじめに

この実験では、Rust の Iterator トレイトについて学びます。このトレイトは、配列などのコレクションに対する反復子を実装するために使用されます。Iterator トレイトでは、反復子に対して next メソッドが定義される必要があり、impl ブロックで手動で実装することも、配列や範囲に対して自動的に定義することもできます。for 構文を使うと、.into_iter() メソッドを使って便利にいくつかのコレクションを反復子に変換することができます。この実験では、反復子としての Fibonacci 数列生成器の例を提供し、next メソッドをどのように定義し、Iterator トレイトをどのように使うかを示しています。また、反復子を操作するための takeskip メソッドの使い方と、配列を反復するための iter メソッドの使い方も示しています。

注: 実験でファイル名が指定されていない場合、好きなファイル名を使うことができます。たとえば、main.rs を使って、rustc main.rs &&./main でコンパイルして実行することができます。

反復子

Iterator トレイトは、配列などのコレクションに対する反復子を実装するために使用されます。

このトレイトでは、next 要素に対してただ 1 つのメソッドが定義される必要があり、これは impl ブロックで手動で定義することも、(配列や範囲の場合のように)自動的に定義することもできます。

一般的なケースにおける便利さとして、for 構文は .into_iter() メソッドを使っていくつかのコレクションを反復子に変換します。

struct Fibonacci {
    curr: u32,
    next: u32,
}

// `Fibonacci` に対して `Iterator` を実装します。
// `Iterator` トレイトでは、`next` 要素に対してただ 1 つのメソッドが定義される必要があります。
impl Iterator for Fibonacci {
    // この型を `Self::Item` を使って参照できます。
    type Item = u32;

    // ここでは、`.curr` と `.next` を使って数列を定義します。
    // 戻り値の型は `Option<T>` です。
    //     * `Iterator` が終了した場合、`None` が返されます。
    //     * それ以外の場合、次の値が `Some` にラップされて返されます。
    // 戻り値の型で `Self::Item` を使っているので、
    // 型を変更しても関数のシグネチャを更新する必要はありません。
    fn next(&mut self) -> Option<Self::Item> {
        let current = self.curr;

        self.curr = self.next;
        self.next = current + self.next;

        // フィボナッチ数列には終点がないので、`Iterator` は
        // 決して `None` を返さず、常に `Some` が返されます。
        Some(current)
    }
}

// フィボナッチ数列生成器を返します。
fn fibonacci() -> Fibonacci {
    Fibonacci { curr: 0, next: 1 }
}

fn main() {
    // `0..3` は、0、1、2 を生成する `Iterator` です。
    let mut sequence = 0..3;

    println!("0..3 に対する 4 つの連続した `next` 呼び出し");
    println!("> {:?}", sequence.next());
    println!("> {:?}", sequence.next());
    println!("> {:?}", sequence.next());
    println!("> {:?}", sequence.next());

    // `for` は、`Iterator` が `None` を返すまで反復します。
    // 各 `Some` 値はアンラップされ、変数(ここでは `i`)に束縛されます。
    println!("`for` を使って 0..3 を反復する");
    for i in 0..3 {
        println!("> {}", i);
    }

    // `take(n)` メソッドは、`Iterator` を最初の `n` 項までに絞ります。
    println!("フィボナッチ数列の最初の 4 項は:");
    for i in fibonacci().take(4) {
        println!("> {}", i);
    }

    // `skip(n)` メソッドは、最初の `n` 項を捨てることで `Iterator` を短縮します。
    println!("フィボナッチ数列の次の 4 項は:");
    for i in fibonacci().skip(4).take(4) {
        println!("> {}", i);
    }

    let array = [1u32, 3, 3, 7];

    // `iter` メソッドは、配列/スライスに対して `Iterator` を生成します。
    println!("次の配列 {:?} を反復する", &array);
    for i in array.iter() {
        println!("> {}", i);
    }
}

まとめ

おめでとうございます!あなたは反復子の実験を完了しました。あなたの技術を向上させるために、LabEx でさらに多くの実験を行って練習してください。