カスタムイテレーター
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フィードバックを取得できます。ローカル設定は不要です。