Rustにはジェネレーターがありますが、それらは非常に実験的なものであり、現在安定版の Rust では利用できません。
安定した Rust 1.0 以降で動作します
Range
具体的な例を処理します。次の構文シュガーで使用できます..
。
fn main() {
let sum: u64 = (0..1_000_000).sum();
println!("{}", sum)
}
Range
存在しなかったら?それをモデル化するイテレータを作成できます!
struct MyRange {
start: u64,
end: u64,
}
impl MyRange {
fn new(start: u64, end: u64) -> MyRange {
MyRange {
start: start,
end: end,
}
}
}
impl Iterator for MyRange {
type Item = u64;
fn next(&mut self) -> Option<u64> {
if self.start == self.end {
None
} else {
let result = Some(self.start);
self.start += 1;
result
}
}
}
fn main() {
let sum: u64 = MyRange::new(0, 1_000_000).sum();
println!("{}", sum)
}
内臓は同じですが、Python バージョンよりも明確です。特に、Python のジェネレーターは状態を追跡します。Rust は明示性を好むため、独自の状態を作成して手動で更新する必要があります。重要な部分はIterator
traitの実装です。イテレータが特定の型 ( ) の値を生成することを指定し、type Item = u64
各反復のステップ実行と、反復の終わりに達したことを伝える方法を処理します。
この例は、ジェネリックを使用する実際の ほど強力ではありませんがRange
、その方法の例を示しています。
ナイトリーRustで動作
Nightly Rustにはジェネレーターがありますが、非常に実験的なものです。作成するには、いくつかの不安定な機能を取り込む必要があります。ただし、Rust 固有の追加がいくつか加えられているため、Python の例にかなり近いように見えます。
// 1.43.0-nightly (2020-02-09 71c7e149e42cb0fc78a8)
#![feature(generators, generator_trait)]
use std::{
ops::{Generator, GeneratorState},
pin::Pin,
};
fn firstn(n: u64) -> impl Generator<Yield = u64, Return = ()> {
move || {
let mut num = 0;
while num < n {
yield num;
num += 1;
}
}
}
現在の Rust のすべてがイテレーターで動作するため、より広いエコシステムで遊ぶために、ジェネレーターをイテレーターに変換するアダプターを作成します。最終的には、そのようなアダプターが標準ライブラリに存在することを期待しています。
struct GeneratorIteratorAdapter<G>(Pin<Box<G>>);
impl<G> GeneratorIteratorAdapter<G>
where
G: Generator<Return = ()>,
{
fn new(gen: G) -> Self {
Self(Box::pin(gen))
}
}
impl<G> Iterator for GeneratorIteratorAdapter<G>
where
G: Generator<Return = ()>,
{
type Item = G::Yield;
fn next(&mut self) -> Option<Self::Item> {
match self.0.as_mut().resume(()) {
GeneratorState::Yielded(x) => Some(x),
GeneratorState::Complete(_) => None,
}
}
}
これで使用できます。
fn main() {
let generator_iterator = GeneratorIteratorAdapter::new(firstn(1_000_000));
let sum: u64 = generator_iterator.sum();
println!("{}", sum);
}
これについて興味深いのは、 の実装よりも強力ではないということですIterator
。たとえば、反復子にはsize_hint
メソッドがあり、反復子の消費者は残りの要素数を把握できます。collect
これにより、コンテナーに ing する際の最適化が可能になります。ジェネレーターにはそのような情報はありません。