Rust中的惰性序列生成
如何创建其他语言所称的惰性序列或“生成器”函数 在Python中,我可以使用Rust中的惰性序列生成,rust,lazy-sequences,Rust,Lazy Sequences,如何创建其他语言所称的惰性序列或“生成器”函数 在Python中,我可以使用yield,如以下示例(来自Python的文档)中所示,以不使用中间列表内存的方式惰性地生成一个可编辑的序列: #生成项目而不是返回列表的生成器 def firstn(n): num=0 当num
yield
,如以下示例(来自Python的文档)中所示,以不使用中间列表内存的方式惰性地生成一个可编辑的序列:
#生成项目而不是返回列表的生成器
def firstn(n):
num=0
当num
如何在Rust中执行类似的操作?Rust 1.0没有生成器功能,因此您必须手动使用 首先,用
next()
方法将Python示例重写为一个类,因为它更接近于在Rust中可能得到的模型。然后,您可以使用实现迭代器
特性的结构在Rust中重写它
您也可以使用返回闭包的函数来获得类似的结果,但我认为不可能让它实现迭代器
特性(因为需要调用它来生成新结果)。Rust确实有生成器,但它们是高度实验性的,目前在稳定锈菌中还没有
在稳定锈1.0及以上的环境中工作
处理您的具体示例。您可以将其与的语法糖一起使用。
:
fn main() {
let sum: u64 = (0..1_000_000).sum();
println!("{}", sum)
}
如果范围不存在怎么办?我们可以创建一个迭代器来建模它
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)
}
由于current 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,
}
}
}
有趣的是,它不如迭代器
的实现强大。例如,迭代器有一个方法,它允许迭代器的使用者知道还有多少元素。这允许在收集
装入容器时进行优化。发电机没有任何此类信息。您可以使用我的stackful Rust,它支持稳定生锈:
#[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);
}
#[宏使用]
外部板条箱发电机;
使用生成器::{generator,Gn};
fn firstn(n:usize)->Generator作为稳定的,您有方便的实用程序。它不是一个协同程序(也就是说,您每次都必须返回),但至少它可以避免您定义另一个结构
from_fn
接受闭包FnMut()->选项
并重复调用它以创建一个迭代器
/->铁锈盒2015
fn firstn(n:u64)->impl std::iter::迭代器{
设mut num=0;
标准:国际热核聚变实验堆:从| fn(移动| |{
让结果;
如果num
也有。它不太通用,但可能更易于使用,因为您只需显式地传递种子值。(即,它需要一个初始值T
和一个后续函数FnMut(&T)->选项来创建一个迭代器
)
fn firstn(n:u64)->impl std::iter::Iterator{
标准热核实验堆(
一些(0),,
移动|&数值|{
如果num+1
然而,Shepmaster的注释也适用于这些实用程序。(tldr:通常手动滚动的迭代器
s内存效率更高)
有趣的是,它不如迭代器
的实现强大。例如,迭代器有一个方法,它允许迭代器的使用者知道还有多少元素。这允许在收集
装入容器时进行优化。发电机没有任何此类信息
(注意:返回impl
是Rust 2018的一项功能。有关详细信息,请参阅)根据确切的顺序,有几个内置迭代器可以使用,例如,或加上a(和/或任何其他组合函数)。(遗憾的是,除了类型之外,还没有其他类型的文档。)我想知道是否有可能编写一个宏,让您定义自定义迭代器结构,但使用较少的样板文件。这个答案非常过时。请参阅“生成器没有任何此类信息”这就是问题所在。生成器的一个主要用例是能够对无限序列执行操作,而不必将无限序列保存在内存中。这种惰性计算有很多应用程序。那么有什么方法可以避免将其转换回迭代器呢?@zer0fool将其转换为迭代器不是问题这里。它仍然可以处理无限序列。迭代器就像一个没有语法糖分的生成器。@zer0fool标准的Rust迭代器已经允许无限序列而不保留整个序列。例如,请参阅。生成器不添加该功能。迭代器有生成器没有的其他信息允许优化。@zer0fool直接使用生成器可以避免转换为迭代器,正如迭代器适配器的主体所示。您将无法在需要迭代器的地方使用它。它可以工作,但并不总是这样。它不是正确的生成器/yieldImagine的最佳替代方法,您需要在返回后返回一些内容你需要睡1秒钟。你不能用std::iter::from_fn
或std::iter::successivers
fn main() {
let generator_iterator = GeneratorIteratorAdapter::new(firstn(1_000_000));
let sum: u64 = generator_iterator.sum();
println!("{}", sum);
}
#[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();