Следующий код работает:
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}>`
Что я должен делать?

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