簡體   English   中英

如何將生成器存儲在結構中?

[英]How can I store a generator in a struct?

我想這樣做

#![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:_ _]`

多虧了通用結構的構造函數中的“預期類型參數”錯誤,我更接近了,在impl之后刪除了通用類型(因為我沒有為任意G實現該結構。工作:

impl Container<G> 
where
    G: Generator<Yield = i32, Return = ()>
{ /* ... */ }
impl Container<Generator<Yield = i32, Return = ()>> { /* ... */ }
impl Container<_> { /* ... */ }

我想我找到了答案,但是如果有人有更好的答案,請隨時發布。 我顯然對此不是很了解,或者我不會問。

為了完整性:需要通用G ,因為生成器就像閉包一樣,每個閉包都有不同的類型(不僅是每個聲明-每個實例也是如此),因為它捕獲了不同的環境。

正如泛型結構的構造函數中的“預期類型參數”錯誤指出的那樣,第一個問題是impl之后的泛型類型。 這意味着該實現是針對外部選擇的T ,但返回的Self具有類型參數的特定值,即生成器之一。

至於如何更換它,

  • impl Container<G> where G: Generator<Yield = i32, Return = ()>

    這是行不通的,因為盡管G是有界的(非常嚴格),但仍然沒有人負責選擇特定的G

  • impl Container<_>

    這不起作用,因為類型推斷不適用於結構實現。 這可能是有道理的-除了“構造函數”之外,對於其他任何東西都不是真正合乎邏輯的。

  • 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() {}

上面的操場和用法示例

並非總是適用的技巧是將生成器(或迭代器,這是非常相似的概念)的創建分成一個單獨的函數。 這使您可以使用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)))
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM