是否可以在Rust的flat_map
中处理不同数量的元素?
根据情况,我需要映射单个enum
元素或enum
元素的向量。
我尝试使用std::iter::once
,但由于once
和Vec::iter
是不同的类型,因此无法从相同的if
条件返回,因此无法正常工作。
enum Enum {
Ident(String),
Val(i32)
}
fn main() {
let my_vec = vec![1, 2, 3];
let condition = true; // Any condition
my_vec.iter()
.flat_map(|x| {
if condition {
std::iter::once(Enum::Ident("id".to_string())).into_iter() /* single Enum element */
} else {
vec![Enum::Val(1), Enum::Val(2)].iter() /* vector of Enum elements */
}
})
.collect::<Vec<Enum>>()
}
|
12 | / if condition {
13 | | std::iter::once(Enum::Ident("id".to_string())).into_iter() /* single Enum element */
| | ---------------------------------------------------------- expected because of this
14 | | } else {
15 | | vec![Enum::Val(1), Enum::Val(2)].iter() /* vector of Enum elements */
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::iter::Once`, found struct `std::slice::Iter`
16 | | }
| |_______________- if and else have incompatible types
|
= note: expected type `std::iter::Once<Enum>`
found type `std::slice::Iter<'_, Enum>`
显而易见的解决方案是在两种情况下都使用向量:
my_vec
.iter()
.flat_map(|_| {
if condition {
vec![Enum::Ident("id".to_string())].into_iter()
} else {
vec![Enum::Val(1), Enum::Val(2)].into_iter()
}
})
.collect::<Vec<Enum>>();
这将导致对单元素向量进行额外分配,但这是一个简单易读的解决方案。如果要避免这种开销,一种选择是使用either
条板箱:
use either::{Left, Right};
enum Enum {
Ident(String),
Val(i32),
}
fn main() {
let my_vec = vec![1, 2, 3];
let _ = my_vec
.iter()
.flat_map(|&x| {
if x > 1 {
Left(std::iter::once(Enum::Ident("id".to_string())))
} else {
Right(vec![Enum::Val(1), Enum::Val(2)].into_iter())
}
})
.collect::<Vec<Enum>>();
}
该板条箱定义了带有变体Either
和Left
的通用枚举Right
。如果双方的类型都支持迭代,则枚举还可以通过分派给相应的基础迭代器类型来支持迭代。