Как я могу хранить генератор в структуре? - PullRequest
0 голосов
/ 08 июня 2018

Я хочу сделать это :

#![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<_> { /* ... */ }

Ответы [ 2 ]

0 голосов
/ 09 июня 2018

Уловка, которая не всегда применима, состоит в том, чтобы разделить создание генератора (или итератора, это удивительно похожие концепции) на отдельную функцию.Это позволяет вам использовать 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)))
    }
}
0 голосов
/ 09 июня 2018

Я думаю, что нашел ответ, но если у кого-то есть лучший ответ, не стесняйтесь писать.Я, очевидно, еще не очень осведомлен об этом, иначе я бы не спросил.

Для полноты: универсальный G необходим, потому что генераторы похожи на замыкания, а каждое замыкание имеет свой тип (не толькокаждое объявление - также каждое создание), поскольку оно захватывает другую среду.

Как указано Ошибка «Ожидаемый параметр типа» в конструкторе универсальной структуры , первой проблемой было универсальноевведите после impl.Это означало, что реализация предназначалась для T, выбранного извне, но вместо этого возвращенное значение Self имело определенное значение для параметра типа, а именно для генератора.

Что касается его замены,

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

    Это не работает, потому что хотя G ограничено (довольно строго), до сих пор никто не отвечает за выбор конкретного G.

  • impl Container<_>

    Это не работает, потому что вывод типов не работает для реализаций структуры.Что, вероятно, имеет смысл - это не будет логично для чего-либо, кроме «конструкторов».

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

    Это не работает, потому что Generator являетсяОбъекты trait и trait не имеют размера (тогда как этот параметр типа должен иметь размер).

Размерность может быть решена.Потребовалось немного попыток, и я не уверен, что это идеально, но добавление Box в реализацию исправило это.Обратите внимание, что Box не является частью Container;очевидно, Box<Generator<...>> также удовлетворяет условию G: Generator<...>?

I думаю это также значительно уменьшает шансы перемещения генератора, что, как я думаю не должно происходить:

Функция 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() {}

Детская площадка длявыше и пример использования .

...