Как определить итератор в Rust над структурой, которая содержит элементы, которые можно повторять? - PullRequest
2 голосов
/ 02 июня 2019

Как определить итератор в Rust над структурой, содержащей элементы, которые уже итерируемы? Вот одна попытка итератора

use rand;

// Structure of items
struct Foo {
    foo: Vec<f64>,
    bar: Vec<i64>,
}

// Iterator for the structure
struct FooIter {
    foo: Iterator,
    bar: Iterator,
}

// Method that provides the iterator for use
impl Foo {
    fn iter(&self) -> FooIter {
        FooIter {
            foo: self.foo.iter().peek(),
            bar: self.bar.iter().peek(),
        }
    }
}

// Item desired from iterator
enum Bar {
    MyFloat(f64),
    MyInt(i64),
}

// Implementation of the iterator
impl Iterator for FooIter {
    type Item = Bar;

    fn next(&mut self) -> Option<Bar> {
        match (self.foo.peek(), self.far.peek()) {
            (Some(_), Some(_)) => {
                if rand::random() {
                    self.foo.next()
                } else {
                    self.bar.next()
                }
            }
            (Some(_), None) => self.foo.next(),
            (None, Some(_)) => self.bar.next(),
            (None, None) => None,
        }
    }
}

// Iterate over a struct
fn main() {
    let fuz = Foo {
        foo: vec![1.2, 2.3, 3.4],
        bar: vec![5, 6],
    };
    for item in fuz.iter() {
        match item {
            Bar::MyFloat(f) => println!("float : {}", f),
            Bar::MyInt(i) => println!("int : {}", i),
        }
    }
}

Короче говоря, структура Foo содержит два вектора, и я бы хотел итератор, который случайным образом переключается между двумя элементами. Конечно, здесь много ошибок, но по сути я не понимаю, как создать структуру, которая содержит итераторы для элементов foo и far, потому что Rust определяет итераторы как черту, а не тип.

Ответы [ 2 ]

4 голосов
/ 02 июня 2019

В какой-то момент вы должны определить, что Item будет производить Iterator, например Iterator<Item = &'a f64>.Давайте упростим и преобразуем в Iterator<Item = f64>, потому что f64 равно Copy, поэтому часто лучше избегать ссылки, если она вам не нужна.

Итак, у нас будет ошибка компиляции:

error[E0277]: the size for values of type `(dyn std::iter::Iterator<Item = f64> + 'static)` cannot be known at compilation time
  --> src/main.rs:11:5
   |
11 |     foo: std::iter::Iterator<Item = f64>,
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `(dyn std::iter::Iterator<Item = f64> + 'static)`
   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
   = note: only the last field of a struct may have a dynamically sized type

Чтобы избежать динамического типа и исправить ошибку одновременно, давайте определим некоторый универсальный тип:

// Iterator for the structure
struct FooIter<F, I> {
    foo: F,
    bar: I,
}

Мы добавим необходимое в нашу реализацию Iterator:

impl<F, I> Iterator for FooIter<F, I>
where
    F: Iterator<Item = f64>,
    I: Iterator<Item = i64>,

И мы должны изменить способ генерации FooIter, на этот раз мы будем использовать магическое ключевое слово impl, чтобы избежать написания реального типа Iterator, который может быть очень длинным и неясным,компилятор выведет тип для нас.Кроме того, мы должны привязать тип к времени жизни &self, потому что он должен быть заимствован до тех пор, пока итератор жив, просто объявить 'a время жизни и добавить + 'a сделает работу:

fn iter<'a>(
    &'a self,
) -> FooIter<impl Iterator<Item = f64> + 'a, impl Iterator<Item = i64> + 'a> {
    FooIter {
        foo: self.foo.iter().copied(),
        bar: self.bar.iter().copied(),
    }
}

Здесь мы заканчиваем основную, следующая проблема в том, что ваш код не выдает Bar типа next(), поэтому мы должны исправить ваш код, также было бы неплохо создать генератор случайных чисел propre.Итак, вот последний фрагмент:

use rand::{rngs::ThreadRng, thread_rng, Rng};

// Structure of items
struct Foo {
    foo: Vec<f64>,
    bar: Vec<i64>,
}

// Iterator for the structure
struct FooIter<'r, F, I> {
    foo: F,
    bar: I,
    rng: &'r mut ThreadRng,
}

// Method that provides the iterator for use
impl Foo {
    fn iter<'a, 'r: 'a>(
        &'a self,
        rng: &'r mut ThreadRng,
    ) -> FooIter<impl Iterator<Item = f64> + 'a, impl Iterator<Item = i64> + 'a> {
        FooIter {
            foo: self.foo.iter().copied(), // nigthly feature, use cloned() for stable
            bar: self.bar.iter().copied(),
            rng,
        }
    }
}

// Item desired from iterator
enum Bar {
    MyFloat(f64),
    MyInt(i64),
}

// Implementation of the iterator
impl<'r, F, I> Iterator for FooIter<'r, F, I>
where
    F: Iterator<Item = f64>,
    I: Iterator<Item = i64>,
{
    type Item = Bar;

    fn next(&mut self) -> Option<Bar> {
        if self.rng.gen() {
            self.foo
                .next()
                .map(|x| Bar::MyFloat(x))
                .or_else(|| self.bar.next().map(|x| Bar::MyInt(x)))
        } else {
            self.bar
                .next()
                .map(|x| Bar::MyInt(x))
                .or_else(|| self.foo.next().map(|x| Bar::MyFloat(x)))
        }
    }
}

// Iterate over a struct
fn main() {
    let fuz = Foo {
        foo: vec![1.2, 2.3, 3.4],
        bar: vec![5, 6],
    };
    for item in fuz.iter(&mut thread_rng()) {
        match item {
            Bar::MyFloat(f) => println!("float : {}", f),
            Bar::MyInt(i) => println!("int : {}", i),
        }
    }
}

Обратите внимание, если вы все еще хотите Peekable<Iterator>, просто сделайте:

struct FooIter<'r, F, I>
where
    F: Iterator<Item = f64>,
    I: Iterator<Item = i64>,
{
    foo: Peekable<F>,
    bar: Peekable<I>,
    rng: &'r mut ThreadRng,
}

// Method that provides the iterator for use
impl Foo {
    fn iter<'a, 'r: 'a>(
        &'a self,
        rng: &'r mut ThreadRng,
    ) -> FooIter<impl Iterator<Item = f64> + 'a, impl Iterator<Item = i64> + 'a> {
        FooIter {
            foo: self.foo.iter().copied().peekable(),
            bar: self.bar.iter().copied().peekable(),
            rng,
        }
    }
}
0 голосов
/ 05 июня 2019

@ Stargateur в основном отсортировал меня, но я хотел включить два отдельных кода для завершения.Ниже приведен фиксированный код, который немного ближе к моей первоначальной попытке, которая работает на Rust 1.34.1:

// Structure of items
struct Foo {
    foo: Vec<f64>,
    far: Vec<i64>,
}

// Iterator for the structure
struct FooIter<FloatIter, IntIter>
where
    FloatIter: Iterator<Item = f64>,
    IntIter: Iterator<Item = i64>,
{
    foo: std::iter::Peekable<FloatIter>,
    far: std::iter::Peekable<IntIter>,
}

// Method that provides the iterator for use
impl Foo {
    fn iter<'a>(
        &'a self,
    ) -> FooIter<impl Iterator<Item = f64> + 'a, impl Iterator<Item = i64> + 'a> {
        FooIter {
            foo: self.foo.iter().cloned().peekable(),
            far: self.far.iter().cloned().peekable(),
        }
    }
}

// Item desired from iterator
enum Bar {
    MyFloat(f64),
    MyInt(i64),
}

// Implementation of the iterator
impl<FloatIter, IntIter> Iterator for FooIter<FloatIter, IntIter>
where
    FloatIter: Iterator<Item = f64>,
    IntIter: Iterator<Item = i64>,
{
    type Item = Bar;

    fn next(&mut self) -> Option<Bar> {
        match (self.foo.peek(), self.far.peek()) {
            (Some(_), Some(_)) => {
                if rand::random() {
                    self.foo.next().map(|x| Bar::MyFloat(x))
                } else {
                    self.far.next().map(|x| Bar::MyInt(x))
                }
            }
            (Some(_), None) => self.foo.next().map(|x| Bar::MyFloat(x)),
            (None, Some(_)) => self.far.next().map(|x| Bar::MyInt(x)),
            (None, None) => None,
        }
    }
}

// Iterate over a struct
fn main() {
    let fuz = Foo {
        foo: vec![1.2, 2.3, 3.4],
        far: vec![5, 6],
    };
    for item in fuz.iter() {
        match item {
            Bar::MyFloat(f) => println!("float : {}", f),
            Bar::MyInt(i) => println!("int : {}", i),
        }
    }
}

Что помогло мне понять, что происходит, так это то, что FooIter параметризует свои аргументы для универсальных типов,Эти типы выводятся с помощью impl Trait в позиции возврата в методе iter для Foo.Тем не менее, я смог написать подобный код без использования этого вывода:

extern crate rand;

// Structure of items
struct Foo {
    foo: Vec<f64>,
    far: Vec<i64>,
}

// Iterator for the structure
struct FooIter<'a> {
    foo: std::iter::Peekable<std::slice::Iter<'a, f64>>,
    far: std::iter::Peekable<std::slice::Iter<'a, i64>>,
}

// Method that provides the iterator for use
impl Foo {
    fn iter<'a>(&'a self) -> FooIter<'a> {
        FooIter {
            foo: self.foo.iter().peekable(),
            far: self.far.iter().peekable(),
        }
    }
}

// Item desired from iterator
enum Bar {
    MyFloat(f64),
    MyInt(i64),
}

// Implementation of the iterator
impl<'a> Iterator for FooIter<'a> {
    type Item = Bar;

    fn next(&mut self) -> Option<Bar> {
        match (self.foo.peek(), self.far.peek()) {
            (Some(_), Some(_)) => {
                if rand::random() {
                    self.foo.next().map(|x| Bar::MyFloat(x.clone()))
                } else {
                    self.far.next().map(|x| Bar::MyInt(x.clone()))
                }
            }
            (Some(_), None) => self.foo.next().map(|x| Bar::MyFloat(x.clone())),
            (None, Some(_)) => self.far.next().map(|x| Bar::MyInt(x.clone())),
            (None, None) => None,
        }
    }
}

// Iterate over a struct
fn main() {
    let fuz = Foo {
        foo: vec![1.2, 2.3, 3.4],
        far: vec![5, 6],
    };
    for item in fuz.iter() {
        match item {
            Bar::MyFloat(f) => println!("float : {}", f),
            Bar::MyInt(i) => println!("int : {}", i),
        }
    }
}

Это почти наверняка неправильный способ сделать что-то, но я хотел посмотреть, возможно ли это.Я определил тип итератора, скомпилировав код:

fn main() {
    let x = vec![1.2, 2.3, 3.4];
    let y: i32 = x.iter().peekable();
}

, что привело к ошибке компилятора:

error[E0308]: mismatched types
 --> junk.rs:4:19
  |
4 |     let y: i32 = x.iter().peekable();
  |                  ^^^^^^^^^^^^^^^^^^^ expected i32, found struct `std::iter::Peekable`
  |
  = note: expected type `i32`
             found type `std::iter::Peekable<std::slice::Iter<'_, {float}>>`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.

Это содержит тип того, что я искал.Опять же, это почти наверняка неправильно, но это помогло мне понять предоставленный ответ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...