如何创建其他语言称为惰性序列或“生成器”功能的语言?
[在Python中,我可以在下面的示例中使用yield
(来自Python的文档)来懒惰地生成一个可迭代的序列,该序列以不使用中间列表的内存的方式进行迭代:
# a generator that yields items instead of returning a list
def firstn(n):
num = 0
while num < n:
yield num
num += 1
sum_of_first_n = sum(firstn(1000000))
如何在Rust中做类似的事情?
Rust 1.0没有生成器功能,因此您必须使用explicit iterators手动进行。
首先,使用next()
方法将您的Python示例重写为类,因为它更接近您可能会在Rust中获得的模型。然后,您可以使用实现Iterator
特性的结构在Rust中重写它。
[您也许还可以使用返回闭包的函数来实现类似的结果,但是我认为不可能实现Iterator
特性(因为需要调用该特性才能生成一个Range
特性)。新结果)。
Rust does有生成器,但它们是高度实验性],目前在稳定的Rust中不可用。
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的实现。我们指定迭代器产生特定类型(Iterator
)的值,然后处理每次迭代的步骤以及如何判断我们已经到达迭代结束。
此示例不如使用泛型的真实type Item = u64
强大,但显示了如何执行此操作的示例。
夜锈Range
,但它们是高度实验性。您需要引入一些不稳定的功能才能创建一个。但是,它看起来pretty接近Python示例,并带有一些Rust特定的附加内容:
does have generators由于当前Rust中的所有内容都在迭代器上运行,所以我们创建了一个适配器,该适配器将生成器转换为迭代器,以便与更广泛的生态系统一起使用。我希望这样的适配器最终会出现在标准库中:
#![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; } } }
现在我们可以使用它:
struct GeneratorIteratorAdapter<G>(G); impl<G> Iterator for GeneratorIteratorAdapter<G> where G: Generator<Return = ()>, { type Item = G::Yield; fn next(&mut self) -> Option<Self::Item> { let me = unsafe { Pin::new_unchecked(&mut self.0) }; match me.resume() { GeneratorState::Yielded(x) => Some(x), GeneratorState::Complete(_) => None, } } }
对此有趣的是,它没有
fn main() { let generator_iterator = GeneratorIteratorAdapter(firstn(1_000_000)); let sum: u64 = generator_iterator.sum(); println!("{}", sum); }
的实现那么强大。例如,迭代器具有Iterator
方法,该方法使迭代器的使用者可以了解剩余多少个元素。size_hint
放入容器时,可以进行优化。生成器没有任何此类信息。
您可以使用支持稳定Rust的堆栈式Rust size_hint
:
从#[macro_use]
extern crate generator;
use generator::{Generator, Gn};
fn firstn(n: usize) -> Generator<'static, (), usize> {
Gn::new_scoped(move |mut s| {
let mut num = 0;
while num < n {
s.yield_(num);
num += 1;
}
done!();
})
}
fn main() {
let sum_of_first_n: usize = firstn(1000000).sum();
println!("sum ={}", sum_of_first_n);
}
开始,您具有方便的let n = 100000;
let range = Gn::new_scoped(move |mut s| {
let mut num = 0;
while num < n {
s.yield_(num);
num += 1;
}
done!();
});
let sum: usize = range.sum();
实用程序。