Как сохранить разнородный список итераторов или объектов, которые можно преобразовать в итераторы, которые можно использовать несколько раз?

#rust

#Ржавчина

Вопрос:

Есть ли хороший способ сохранить разнородный список итераторов или объектов, которые можно преобразовать в итераторы, которые можно использовать несколько раз? У меня ситуация, когда я хотел бы выполнить итерацию по вектору несколькими способами. Чаще всего эти индексы будут поступать из диапазона или другого вектора, но это не гарантия. Кроме того, эти индексы будут использоваться несколько раз, поэтому они должны быть повторно использованы. Есть ли хороший способ добиться этого? В качестве одной попытки у нас есть код:

 // Create a struct to hold a list of items that generate indices and a vector
struct Foo {
    data: Vec<f64>,
    index_list: Vec<Box<dyn Iterator<Item = usize>>>,
}

// Function that iterates over elements in the data
fn bar(f: amp;mut Foo) {
    for indices in amp;mut f.index_list {
        println!("Start of iteration");
        for i in indices {
            println!("{}", f.data[i])
        }
    }
}

// Test the routine
fn main() {
    let mut f = Foo {
        data: vec![0.1, 1.2, 2.3, 3.4],
        index_list: vec![
            Box::new((0..=1).into_iter()),
            Box::new(vec![2, 1, 3].into_iter()),
        ],
    };

    // Want these two functions to not consume the iterators and produce the
    // same result
    bar(amp;mut f);
    bar(amp;mut f);
}
  

Это создает

 Start of iteration
0.1
1.2
Start of iteration
2.3
1.2
3.4
Start of iteration
Start of iteration
  

чего и следовало ожидать. Итераторы из Foo структуры используются при первом вызове bar . Я хотел бы перейти f к foo неизменяемым образом, чтобы несколько вызовов foo возвращали один и тот же результат. Я также категорически не хочу собирать индексы в вектор, поскольку фактический вариант использования будет включать очень длинный список индексов, которые сами по себе очень велики. Таким образом, существуют ограничения памяти, которые не обязательно присутствуют в этом примере.

В любом случае, удаление изменчивости выше приводит к ошибке компилятора:

 error[E0277]: `amp;Box<dyn Iterator<Item = usize>>` is not an iterator
  --> src/main.rs:14:18
   |
14 |         for i in indices {
   |                  ^^^^^^^ `amp;Box<dyn Iterator<Item = usize>>` is not an iterator
   |
   = help: the trait `Iterator` is not implemented for `amp;Box<dyn Iterator<Item = usize>>`
   = note: `Iterator` is implemented for `amp;mut std::boxed::Box<dyn std::iter::Iterator<Item = usize>>`, but not for `amp;std::boxed::Box<dyn std::iter::Iterator<Item = usize>>`
   = note: required because of the requirements on the impl of `IntoIterator` for `amp;Box<dyn Iterator<Item = usize>>`
   = note: required by `into_iter`

error: aborting due to previous error

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

Попытка клонировать индексы дает:

 error[E0277]: `amp;Box<dyn Iterator<Item = usize>>` is not an iterator
  --> src/main.rs:14:18
   |
14 |         for i in indices.clone() {
   |                  ^^^^^^^^^^^^^^^ `amp;Box<dyn Iterator<Item = usize>>` is not an iterator
   |
   = help: the trait `Iterator` is not implemented for `amp;Box<dyn Iterator<Item = usize>>`
   = note: `Iterator` is implemented for `amp;mut std::boxed::Box<dyn std::iter::Iterator<Item = usize>>`, but not for `amp;std::boxed::Box<dyn std::iter::Iterator<Item = usize>>`
   = note: required because of the requirements on the impl of `IntoIterator` for `amp;Box<dyn Iterator<Item = usize>>`
   = note: required by `into_iter`

error: aborting due to previous error
  

и попытка использовать cloned on index_list дает:

 error[E0277]: the trait bound `dyn Iterator<Item = usize>: Clone` is not satisfied
  --> src/main.rs:12:40
   |
12 |     for indices in f.index_list.iter().cloned() {
   |                                        ^^^^^^ the trait `Clone` is not implemented for `dyn Iterator<Item = usize>`
   |
   = note: required because of the requirements on the impl of `Clone` for `Box<dyn Iterator<Item = usize>>`

error[E0277]: the trait bound `dyn Iterator<Item = usize>: Clone` is not satisfied
  --> src/main.rs:12:20
   |
12 |     for indices in f.index_list.iter().cloned() {
   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `dyn Iterator<Item = usize>`
   |
   = note: required because of the requirements on the impl of `Clone` for `Box<dyn Iterator<Item = usize>>`
   = note: required because of the requirements on the impl of `Iterator` for `Cloned<std::slice::Iter<'_, Box<dyn Iterator<Item = usize>>>>`
   = note: required because of the requirements on the impl of `IntoIterator` for `Cloned<std::slice::Iter<'_, Box<dyn Iterator<Item = usize>>>>`
   = note: required by `into_iter`

error: aborting due to 2 previous errors
  

Ответ №1:

Вы можете сохранить список функций, которые возвращают эти итераторы:

 struct Foo<'a> {
    data: Vec<f64>,
    index_list: Vec<amp;'a dyn Fn() -> Box<dyn Iterator<Item = usize>>>,
}

fn bar(f: amp;mut Foo) {
    for indices in amp;mut f.index_list {
        println!("Start of iteration");
        for i in indices() {
            println!("{}", f.data[i])
        }
    }
}

fn main() {
    let mut f = Foo {
        data: vec![0.1, 1.2, 2.3, 3.4],
        index_list: vec![
            amp;|| Box::new((0..=1).into_iter()),
            amp;|| Box::new(vec![2, 1, 3].into_iter()),
        ],
    };

    bar(amp;mut f);
    bar(amp;mut f);
}

  

Комментарии:

1. Это работает. Спасибо! Один вопрос: что насчет системы типов, требующей закрытия? Я бы подумал, что было бы возможно либо что-то, что реализует, IntoIterator либо вызов cloned вывода из итератора.

2. @wyer33 Проблема в том, что итераторы, как правило, одноразовые. После увеличения он не может вернуться назад. Некоторые итераторы вы можете .clone() (нет .cloned() , но .clone() на самом итераторе), но не все.