我有一个有两个变体的枚举。这些变体之一包含 Vec,另一个包含 BTreeMap。我希望能够迭代这两个包含。实际上,我喜欢“按摩”Vec,使其表现得像 BTreeMap,其中值固定为 1。设置如下:
pub struct Sketch {
pub name: String,
pub hashes: Vec<u64>,
}
pub struct WeightedSketch {
pub name: String,
pub hashes: BTreeMap<u64, u32>,
}
pub enum SketchType {
Unweighted(Sketch),
Weighted(WeightedSketch),
}
impl SketchType {
pub fn hashes(&self) -> Iter<u64, u32> {
match self {
SketchType::Weighted(sketch) => sketch.hashes.iter(),
SketchType::Unweighted(sketch) => sketch.hashes.iter().map(|hash| (*hash, 1 as u32)).collect::<BTreeMap<u64, u32>>().iter(),
}
}
}
这可以编译,但似乎不是正确的方法。作为一个简单的示例,我希望能够执行以下操作,无论 SketchType 的变体如何:
fn do_work(sketch: &SketchType) -> u64 {
sketch.values().map(|v| *v as u64).sum()
}
枚举是正确的方法吗?我是否需要以某种方式实现 SketchType 的迭代器特征?
谢谢, 多诺万
这是您正在寻找的东西吗?
use std::collections::BTreeMap;
use itertools::{Itertools, Either}; // 0.11.0
pub struct Sketch {
pub name: String,
pub hashes: Vec<u64>,
}
pub struct WeightedSketch {
pub name: String,
pub hashes: BTreeMap<u32, u64>,
}
pub enum SketchType {
Unweighted(Sketch),
Weighted(WeightedSketch),
}
impl SketchType {
/// An iterator through the hash values.
fn values(&self) -> impl Iterator<Item=u64> + '_ {
// To reconcile the fact that each branch returns a different type of
// iterator, we make use of `itertools::Either`, which is designed
// exactly for that.
match *self {
SketchType::Unweighted(ref sketch) =>
Either::Left(sketch.hashes.iter().cloned()),
SketchType::Weighted(ref sketch) =>
Either::Right(sketch.hashes.values().cloned())
}
}
/// Look, `do_work` works!
fn do_work(&self) -> u64 {
self.values().sum()
}
}