pub fn up_to(limit: u64) -> impl Generator<Yield = u64, Return = u64> {
move || {
for x in 0..limit {
yield x;
}
return limit;
}
}
impl
是什么意思?这如何用普通的 Rust 或 C++ 实现?
impl Trait
语法,它允许程序员避免命名泛型类型。该功能从 Rust 1.26 开始可用。
在这里,它用在返回位置中,表示“返回的类型将实现这个特征,这就是我要告诉你的”。在这种情况下,请注意函数的所有返回路径必须返回完全相同的具体类型。
该语法也可以用在参数位置,在这种情况下,调用者决定传递什么具体类型。
另请参阅:
是什么意思?impl
正如 Matthieu 所解释的,
impl X
的意思是“返回特质 X
的具体实现”。如果没有这个,您可以选择返回实现该特征的具体类型,例如UpToImpl
,或通过返回 Box<Generator>
来擦除类型。前者需要公开类型,而后者则需要动态分配和虚拟调度的运行时成本。更重要的是,这是生成器情况的关键,前一种方法阻止返回闭包,因为闭包返回匿名类型的值。
这如何用普通 Rust 或 C++ 实现?
如果您的意思是如何实现
up_to
,并且希望在不产生分配开销的情况下实现它,则必须放弃使用闭包并手动将生成器重写为实现Generator
特征的状态机:
#![feature(generator_trait)]
use std::{
ops::{Generator, GeneratorState},
pin::Pin,
};
pub struct UpToImpl {
limit: u64,
x: u64,
}
impl Generator for UpToImpl {
type Yield = u64;
type Return = u64;
fn resume(mut self: Pin<&mut Self>) -> GeneratorState<u64, u64> {
let x = self.x;
if x < self.limit {
self.x += 1;
GeneratorState::Yielded(x)
} else {
GeneratorState::Complete(self.limit)
}
}
}
pub fn up_to(limit: u64) -> UpToImpl {
UpToImpl { x: 0, limit }
}
fn main() {
let mut v = Box::pin(up_to(3));
println!("{:?}", v.as_mut().resume());
println!("{:?}", v.as_mut().resume());
println!("{:?}", v.as_mut().resume());
println!("{:?}", v.as_mut().resume());
}
这种转换本质上是 Rust 编译器在给定包含
yield
的闭包时在幕后执行的操作,只不过与 UpToImpl
等效的生成类型是匿名的。 (类似但更简单的转换用于将普通闭包转换为实现 Fn
特征之一的匿名类型的值。)
返回
impl Generator
和具体类型之间还有另一个区别。当返回 UpToImpl
时,该类型必须是公共的,因此成为函数签名的一部分。例如,允许调用者执行以下操作:
let x: UpToImpl = up_to(10);
如果
UpToImpl
被重命名,或者如果您决定切换到使用生成器闭包,该代码将会中断。
这个答案中的
up_to
即使更改为返回impl Generator
也会编译,因此它是实现最大灵活性的更好选择。当 impl Generator
返回时,调用者不能依赖或引用具体的返回类型。返回类型可以切换到实现该特征的any类型,包括匿名闭包,而不会损失向后兼容性。
另请参阅: