如何组合 iter()、iter::once() 和 iter::empty() [重复]

问题描述 投票:0回答:1

以下代码有效:

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}>`

我该怎么办?

rust
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
*/
© www.soinside.com 2019 - 2024. All rights reserved.