我想做this:
#![feature(nll)]
#![feature(generators, generator_trait)]
use std::ops::Generator;
struct Container<G: Generator<Yield = i32, Return = ()>> {
generator: G
}
impl<G: Generator<Yield = i32, Return = ()>> Container<G> {
pub fn new() -> Self {
let q = 42;
Container{ generator: || {
yield 2i32 * q;
} }
}
}
fn main() {}
我收到此错误:
error[E0308]: mismatched types
--> src/main.rs:12:31
|
| Container{ generator: || {
| _______________________________^
| | yield 2i32 * q;
| | } }
| |_________^ expected type parameter, found generator
|
= note: expected type `G`
found type `[generator@src/main.rs:12:31: 14:10 q:_ _]`
感谢"Expected type parameter" error in the constructor of a generic struct我离我更近了,在impl
之后删除了泛型类型(因为我没有为任意G
实现结构。我尝试了这些变体,没有一个工作:
impl Container<G>
where
G: Generator<Yield = i32, Return = ()>
{ /* ... */ }
impl Container<Generator<Yield = i32, Return = ()>> { /* ... */ }
impl Container<_> { /* ... */ }
答案 0 :(得分:1)
我想我找到了答案,但如果有人有更好的答案,请随意发帖。我显然对这方面知之甚少,或者我不会问。
为了完整性:需要泛型G
,因为生成器就像闭包,每个闭包都有不同的类型(不仅仅是每个声明 - 每个实例化),因为它捕获了不同的环境。
正如"Expected type parameter" error in the constructor of a generic struct所指出的,第一个问题是impl
之后的泛型类型。这意味着实现是针对外部选择的T
,但返回的Self
具有类型参数的特定值,即生成器的一个。
至于如何更换它,
impl Container<G> where G: Generator<Yield = i32, Return = ()>
这不起作用,因为尽管G
有限(非常严格),但仍然没有人负责选择特定的G
。
impl Container<_>
这不起作用,因为类型推断不适用于struct实现。这可能是有意义的 - 除了'构造函数'之外,它对任何事情都不合逻辑。
impl Container<Generator<Yield = i32, Return = ()>>
这不起作用,因为Generator
是一个特征,特征对象的大小没有(而这个类型参数的大小应该是这样)。
可以解决尺寸问题。我花了一些尝试,但我不确定它是否完美,但在实现中添加了Box
修复了它。请注意,Box
不属于Container
;显然Box<Generator<...>>
也满足约束G: Generator<...>
?
我认为它也大大降低了生成器被移动的几率,我认为不应该发生:
函数
resume
不安全,因为它可以在不可移动的生成器上使用。在这样的调用之后,不可移动的生成器不能再次移动,但编译器不强制执行此操作。
完整的代码:
#![feature(nll)]
#![feature(generators, generator_trait)]
use std::ops::Generator;
struct Container<G>
where
G: Generator<Yield = i32, Return = ()>,
{
generator: G,
}
impl Container<Box<Generator<Yield = i32, Return = ()>>> {
pub fn new() -> Self {
let q = 42;
Container {
generator: Box::new(move || {
yield 1i32 * q;
yield 2i32 * q;
yield 3i32 * q;
}),
}
}
}
fn main() {}
答案 1 :(得分:1)
一直不适用的技巧是将生成器(或迭代器,这些是非常相似的概念)的创建拆分为单独的函数。这允许您使用impl Trait
:
fn container_core(q: i32) -> impl Generator<Yield = i32, Return = ()> {
move || {
yield 1 * q;
yield 2 * q;
yield 3 * q;
}
}
impl<G> Container<G>
where
G: Generator<Yield = i32, Return = ()>,
{
pub fn new(generator: G) -> Self {
Container { generator }
}
}
fn main() {
let x = Container::new(container_core(42));
}
您仍然无法命名x
的类型,因此您无法将其存储在结构中,因此根本问题尚未解决。当然,您可以结合答案:
impl Container<Box<Generator<Yield = i32, Return = ()>>> {
fn new_boxed(q: i32) -> Self {
Container::new(Box::new(container_core(q)))
}
}