如何使用reduce()从Vec<Enum>中查找最大值?
Rust 用 fold/reduce 从枚举中提取结构体并查找最大值
一、针对所有枚举均为First的场景(符合你的假设)
直接用reduce即可,在闭包中匹配枚举提取d字段进行比较:
#[derive(Debug)] struct Data { d: u64, } #[derive(Debug)] enum DataEnum { First(Data), Second, } fn main() { let v = vec![ DataEnum::First(Data{d: 10}), DataEnum::First(Data{d: 5}), DataEnum::First(Data{d: 15}), DataEnum::First(Data{d: 13}), ]; let max_item = v.iter() .reduce(|a, b| { // 提取a的d值,非First则panic(符合你的假设) let DataEnum::First(a_data) = a else { panic!("Unexpected variant: {:?}", a) }; // 提取b的d值 let DataEnum::First(b_data) = b else { panic!("Unexpected variant: {:?}", b) }; // 返回较大的那个元素 if b_data.d > a_data.d { b } else { a } }) .unwrap(); // 向量非空,直接unwrap println!("found max: {:?}", max_item); }
这里用了Rust 1.65+的else分支匹配语法,比传统match更简洁。
二、处理混合枚举类型的场景(包含Second变体)
如果向量中可能存在Second,可以选择忽略无效变体或返回错误,以下是两种方案:
方案1:忽略Second,只处理First
用filter_map先过滤出有效元素,再执行reduce:
fn main() { let v = vec![ DataEnum::First(Data{d: 10}), DataEnum::Second, DataEnum::First(Data{d: 15}), DataEnum::First(Data{d: 13}), ]; let max_item = v.iter() .filter_map(|item| match item { // 保留First变体,同时绑定元素和对应的d值 DataEnum::First(data) => Some((item, data.d)), // 过滤掉Second DataEnum::Second => None, }) .reduce(|(a_item, a_d), (b_item, b_d)| { if b_d > a_d { (b_item, b_d) } else { (a_item, a_d) } }) // 提取最终的元素,若无有效元素则panic .map(|(item, _)| item) .unwrap_or_else(|| panic!("No valid First variants found")); println!("found max: {:?}", max_item); }
方案2:遇到Second返回错误(更安全)
用try_fold处理可能的错误,返回Result类型:
#[derive(Debug)] struct Data { d: u64, } #[derive(Debug)] enum DataEnum { First(Data), Second, } fn find_max(data: &[DataEnum]) -> Result<&DataEnum, &'static str> { data.iter() .try_fold(None, |acc, current_item| { // 提取当前元素的d值,遇到Second返回错误 let current_d = match current_item { DataEnum::First(data) => data.d, DataEnum::Second => return Err("Encountered invalid Second variant"), }; Ok(match acc { // 初始状态,直接保留当前元素 None => Some(current_item), // 与之前的最大值比较 Some(prev_item) => { let prev_d = match prev_item { DataEnum::First(data) => data.d, _ => unreachable!("Accumulator only holds valid First variants"), }; if current_d > prev_d { Some(current_item) } else { Some(prev_item) } } }) }) // 处理空向量的情况 .and_then(|max_opt| max_opt.ok_or("Vector contains no elements")) } fn main() { let v = vec![ DataEnum::First(Data{d: 10}), DataEnum::Second, DataEnum::First(Data{d: 15}), ]; match find_max(&v) { Ok(max_item) => println!("found max: {:?}", max_item), Err(e) => println!("Error: {}", e), } }
核心逻辑说明
reduce适合无初始值的迭代计算,直接在迭代元素间两两比较filter_map可以提前过滤无效枚举,减少后续闭包中的匹配逻辑try_fold允许在迭代过程中返回错误,替代panic实现更优雅的错误处理- 枚举匹配时,使用
let ... else语法(Rust 1.65+)可以简化代码,避免嵌套match
内容的提问来源于stack exchange,提问作者Igor Lautar
相关产品推荐
相关产品推荐

