0Pricing
Learn Rust Coding · レッスン

カスタムイテレーター

Iteratorを実装します

「カスタムイテレーター」はCoddyKit上の無料Learn Rust Codingレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはLearn Rust Coding学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Learn Rust Codingコースには全4レッスンが含まれています。

独自のイテレータを作る

組み込みのイテレータだけに限られるわけではありません。独自の型にIteratorトレイトを実装すると、すべてのアダプターとコンシューマを無料で利用できます。

用意する必要があるのは、Item型とnextメソッドだけです。

カウンタ構造体

まず、イテレータの状態を保持する構造体を作ります。単純なカウンターに必要なのは、現在の値だけです。

struct Counter {
    count: u32,
}

fn main() {
    let c = Counter { count: 0 };
    println!("start at {}", c.count);
}

nextを実装する

構造体にIteratorを実装します。type Itemを設定し、状態を進めるnextを記述します。停止条件に達するまではSomeを返し、その後はNoneを返します。

struct Counter { count: u32 }

impl Iterator for Counter {
    type Item = u32;
    fn next(&mut self) -> Option<u32> {
        if self.count < 5 {
            self.count += 1;
            Some(self.count)
        } else {
            None
        }
    }
}

fn main() {
    let mut c = Counter { count: 0 };
    println!("{:?}", c.next());
    println!("{:?}", c.next());
}

forループで使う

nextがあれば、独自の型を標準的なイテレータと同じようにforループで使えます。

struct Counter { count: u32 }

impl Iterator for Counter {
    type Item = u32;
    fn next(&mut self) -> Option<u32> {
        if self.count < 5 { self.count += 1; Some(self.count) } else { None }
    }
}

fn main() {
    for n in (Counter { count: 0 }) {
        print!("{} ", n);
    }
    println!();
}

アダプターとコンシューマを無料で利用する

1つのメソッドを実装するだけで、イテレータのツール一式を利用できるようになります。ここでは、対応するカウンター値の二乗を合計します。

struct Counter { count: u32 }

impl Iterator for Counter {
    type Item = u32;
    fn next(&mut self) -> Option<u32> {
        if self.count < 5 { self.count += 1; Some(self.count) } else { None }
    }
}

fn main() {
    let total: u32 = Counter { count: 0 }.map(|x| x * 2).sum();
    println!("{}", total);
}

コンストラクタメソッド

ユーザーが内部フィールドを直接操作しなくて済むように、new関数を追加します。これによりコードがすっきりし、フィールドを非公開に保てます。

struct Counter { count: u32 }

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

impl Iterator for Counter {
    type Item = u32;
    fn next(&mut self) -> Option<u32> {
        if self.count < 3 { self.count += 1; Some(self.count) } else { None }
    }
}

fn main() {
    let v: Vec<u32> = Counter::new().collect();
    println!("{:?}", v);
}

フィボナッチイテレータ

イテレータは、より複雑な状態も保持できます。フィボナッチジェネレータは直前の2つの値を保持し、nextが呼び出されるたびに更新します。

struct Fib { a: u64, b: u64 }

impl Iterator for Fib {
    type Item = u64;
    fn next(&mut self) -> Option<u64> {
        let current = self.a;
        self.a = self.b;
        self.b = current + self.b;
        Some(current)
    }
}

fn main() {
    let fib = Fib { a: 0, b: 1 };
    let seq: Vec<u64> = fib.take(8).collect();
    println!("{:?}", seq);
}

無限イテレータも問題ない

フィボナッチイテレータはNoneを返すことがなく、無限に続きます。遅延評価によって、値は要求されたときにだけ生成されるため安全です。takeを使って範囲を制限しましょう。

struct Fib { a: u64, b: u64 }

impl Iterator for Fib {
    type Item = u64;
    fn next(&mut self) -> Option<u64> {
        let c = self.a;
        self.a = self.b;
        self.b = c + self.b;
        Some(c)
    }
}

fn main() {
    let big = Fib { a: 0, b: 1 }.nth(20);
    println!("{:?}", big);
}

ラッパー型を反復処理する

データを借用するヘルパー構造体にIteratorを実装することもよくあります。ここでは、内部に保持した範囲から2つおきに数値を生成するステッパーを作ります。

struct EvenUpTo { current: u32, max: u32 }

impl Iterator for EvenUpTo {
    type Item = u32;
    fn next(&mut self) -> Option<u32> {
        if self.current > self.max { return None; }
        let value = self.current;
        self.current += 2;
        Some(value)
    }
}

fn main() {
    let evens: Vec<u32> = (EvenUpTo { current: 0, max: 10 }).collect();
    println!("{:?}", evens);
}

独自のイテレータを作る理由

独自のイテレータを使うと、コレクション全体を確保せずに値をストリーミングしたり、無限シーケンスや計算によるシーケンスを表現したり、使い慣れた合成可能なインターフェースを呼び出し側に提供したりできます。

小さなnextメソッド1つで、エコシステム全体を利用できるようになります。

設計のヒント

状態は最小限に保ち、最後には正確に1回Noneを返します(無限イテレータでは一度も返しません)。また、遅延評価のコストを低く保つため、nextの中で重い処理を行わないようにします。

クイックチェック

Iteratorトレイトの実装について確認しましょう。

まとめ

独自のイテレータを構築しました。

  • 構造体に状態を保持し、impl Iteratorを記述します
  • type Itemを定義し、nextを記述します
  • アダプターとコンシューマをすぐに無料で利用できます
  • イテレータは有限にも無限にもできます。無限イテレータの範囲を制限するにはtakeを使います

よくある質問

「カスタムイテレーター」レッスンは無料ですか?

はい。「カスタムイテレーター」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Learn Rust Codingコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Learn Rust Codingコースには全4レッスンが含まれています。

「カスタムイテレーター」で何を学びますか?

Iteratorを実装します ブラウザで直接実行するハンズオンコードでLearn Rust Codingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Learn Rust Codingを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのLearn Rust Codingは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「カスタムイテレーター」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このLearn Rust Codingレッスンでコードを書いて実行できますか?

はい。すべてのLearn Rust Codingレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Iteratorトレイト
  2. map、filter、collect
  3. アダプターとコンシューマー
  4. カスタムイテレーター
← Learn Rust Codingに戻る