Как я могу связать два отдельных набора полей в качестве изменяемого итератора, если оба поля необязательны?

У меня есть структура данных Baz, которую я хочу изменять, где бы она ни находилась внутри инкапсулирующей структуры данных.

Инкапсулирующие объекты живут в Option<Vec<_>>, и поэтому я пытаюсь создать пустой итератор, а затем соединить его со следующим итератором, но не могу получить правильный пустой тип:

struct Foo {
    id: i32,
    bars: Option<Vec<Bar>>,
    bazs: Option<Vec<Baz>>,
}
struct Bar {
    id: i32,
    bazs: Option<Vec<Baz>>,
}
struct Baz {
    id: i32,
}

fn get_iter<'a>(foos: &'a mut Vec<Foo>) -> impl Iterator<Item = &'a mut Baz> {
    foos.iter_mut().flat_map(|foo| {
        let foo_bazs = if let Some(foo_bazs) = foo.bazs.as_mut() {
            foo_bazs.iter_mut()
        } else {
            std::iter::empty()
        };

        let bar_bazs = if let Some(foo_bars) = foo.bars.as_mut() {
            foo_bars.iter_mut().flat_map(|foo_bars| {
                if let Some(bar_bazs) = foo_bars.bazs.as_mut() {
                    bar_bazs.iter_mut()
                } else {
                    std::iter::empty()
                }
            })
        } else {
            std::iter::empty()
        };

        foo_bazs.chain(bar_bazs)
    })
}

fn main() {}

Этот код дает:

error[E0308]: `if` and `else` have incompatible types
  --> src/main.rs:19:13
   |
16 |           let foo_bazs = if let Some(foo_bazs) = foo.bazs.as_mut() {
   |  ________________________-
17 | |             foo_bazs.iter_mut()
   | |             ------------------- expected because of this
18 | |         } else {
19 | |             std::iter::empty()
   | |             ^^^^^^^^^^^^^^^^^^ expected `IterMut<'_, Baz>`, found `Empty<_>`
20 | |         };
   | |_________- `if` and `else` have incompatible types
   |
   = note: expected struct `std::slice::IterMut<'_, Baz>`
              found struct `std::iter::Empty<_>`

error[E0308]: `if` and `else` have incompatible types
  --> src/main.rs:27:21
   |
24 | /                 if let Some(bar_bazs) = foo_bars.bazs.as_mut() {
25 | |                     bar_bazs.iter_mut()
   | |                     ------------------- expected because of this
26 | |                 } else {
27 | |                     std::iter::empty()
   | |                     ^^^^^^^^^^^^^^^^^^ expected `IterMut<'_, Baz>`, found `Empty<_>`
28 | |                 }
   | |_________________- `if` and `else` have incompatible types
   |
   = note: expected struct `std::slice::IterMut<'_, Baz>`
              found struct `std::iter::Empty<_>`

For more information about this error, try `rustc --explain E0308`.
error: could not compile `rust_test` (bin "rust_test") due to 2 previous errors
[Finished running. Exit status: 101]

Если я поменяю std::iter:empty() на Default::default(), ржавчина будет меньше жаловаться:

error[E0277]: the trait bound `FlatMap<std::slice::IterMut<'_, Bar>, std::slice::IterMut<'_, Baz>, {closure@src/main.rs:23:42: 23:52}>: Default` is not satisfied
  --> src/main.rs:31:13
   |
31 |             Default::default()
   |             ^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `FlatMap<std::slice::IterMut<'_, Bar>, std::slice::IterMut<'_, Baz>, {closure@src/main.rs:23:42: 23:52}>`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `rust_test` (bin "rust_test") due to 1 previous error
[Finished running. Exit status: 101]

Как вы можете/необязательно объединять итераторы в цепочку?

Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
0
0
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Option::iter_mut возвращает итератор, который возвращает один элемент, если Some, или ни одного элемента, если None. Вы можете просто использовать это и сгладить результат ( игровая площадка):

foos.iter_mut().flat_map(|foo| {
    foo.bazs.iter_mut().flatten().chain(
        foo.bars
            .iter_mut()
            .flatten()
            .flat_map(|bar| bar.bazs.iter_mut().flatten()),
    )
})

Другие вопросы по теме