You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 20:05:23