Как объединить iter(), iter::once() и iter::empty()

Следующий код работает:

let a = [1, 2, 3].iter();
let b = iter::once(&456);

for i in a.chain(b) {
    println!("{}", i);
}

Выход:

1
2
3
456

Но теперь мне нужно изменить b (в зависимости от некоторых условий) на iter() или iter::once, например.

let a = [1, 2, 3].iter();
let b = if some_condition {
    [4, 5, 6].iter()
} else {
    iter::once(&456)
};

for i in a.chain(b) {
    println!("{}", i);
}

Но я получил:

error[E0308]: `if` and `else` have incompatible types
   |
   |       let b = if some_condition {
   |  _____________-
   | |         [4, 5, 6].iter()
   | |         ---------------- expected because of this
   | |     } else {
   | |         iter::once(&456)
   | |         ^^^^^^^^^^^^^^^^ expected `Iter<'_, {integer}>`, found `Once<&{integer}>`
   | |     };
   | |_____- `if` and `else` have incompatible types
   |
   = note: expected struct `std::slice::Iter<'_, {integer}>`
              found struct `std::iter::Once<&{integer}>`

Что я должен делать?

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

Ответы 1

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

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

fn main() {
    for attempt in 0..2 {
        println!("~~~~ attempt = {} ~~~~", attempt);
        let a = [1, 2, 3].iter();
        let b: Box<dyn Iterator<Item = &i32>> = if attempt == 0 {
            Box::new([4, 5, 6].iter())
        } else {
            Box::new(std::iter::once(&456))
        };
        for i in a.chain(b) {
            println!("{}", i);
        }
    }
}
/*
~~~~ attempt=0 ~~~~
1
2
3
4
5
6
~~~~ attempt=1 ~~~~
1
2
3
456
*/

Предыдущее решение рассматривало более общий случай: два источника данных сильно различаются, но в конечном итоге мы хотим получить результат &i32.
Однако, если проблема действительно похожа на пример в вопросе, мы можем просто представить, что единственное значение — это срез.

fn main() {
    for attempt in 0..2 {
        println!("~~~~ attempt = {} ~~~~", attempt);
        let a = [1, 2, 3].iter();
        let b = if attempt == 0 {
            &[4, 5, 6]
        } else {
            std::slice::from_ref(&456)
        }
        .iter();
        for i in a.chain(b) {
            println!("{}", i);
        }
    }
}
/*
~~~~ attempt=0 ~~~~
1
2
3
4
5
6
~~~~ attempt=1 ~~~~
1
2
3
456
*/

Для стирания типа вы также можете использовать или, чтобы избежать выделения, но вместо once и массива я бы использовал срез длиной один и срез длиной 3, так что стирание типа вообще не требуется.

Masklinn 23.04.2024 17:38

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