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

如何在Rust中通过.max_by_key()传播Result错误?

解决Rust中带错误传播的浮点数最大值查找问题

问题描述

  • 现有函数float_or_err(i: i32) -> Result<f64, ErrorKind>,接收整数返回浮点数或错误
  • 需要实现max_by_float_or_err(arr: &[i32]) -> Result<i32, ErrorKind>:
    • 返回数组中使float_or_err(i)结果最大的整数
    • 若任意调用float_or_err出错,直接传播该错误
  • 已选用ordered_float crate的OrderedFloat<f64>解决浮点数全序问题,但使用.max_by_key()时,闭包返回Result<OrderedFloat<f64>, _>因未实现Ord报错,且受孤儿规则限制无法为该Result实现Ord;闭包内无法用?,自定义结构体包装Result又丢失原有方法。

解决方案

可以通过**用try_fold替代max_by_key**实现需求,既满足错误传播,又无需手动编写循环。

代码实现

use ordered_float::OrderedFloat;
use std::error::Error;

// 自定义错误类型示例
#[derive(Debug)]
enum ErrorKind {
    InvalidInput,
    EmptyArray,
}

impl Error for ErrorKind {}

impl std::fmt::Display for ErrorKind {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ErrorKind::InvalidInput => write!(f, "Invalid input integer"),
            ErrorKind::EmptyArray => write!(f, "Input array is empty"),
        }
    }
}

// 示例业务函数
fn float_or_err(i: i32) -> Result<f64, ErrorKind> {
    if i < 0 {
        Err(ErrorKind::InvalidInput)
    } else {
        Ok(i as f64 * 1.2)
    }
}

fn max_by_float_or_err(arr: &[i32]) -> Result<i32, ErrorKind> {
    arr.iter().try_fold(None, |acc, &num| {
        // 转换为OrderedFloat,出错直接传播
        let current_val = OrderedFloat(float_or_err(num)?);
        // 比较并更新最大值
        Ok(match acc {
            None => Some((current_val, num)),
            Some((max_val, max_num)) => {
                if current_val > max_val {
                    Some((current_val, num))
                } else {
                    Some((max_val, max_num))
                }
            }
        })
    })
    // 处理空数组情况
    .and_then(|opt| opt.ok_or(ErrorKind::EmptyArray))
    // 提取最终的整数结果
    .map(|(_, num)| num)
}

fn main() -> Result<(), Box<dyn Error>> {
    let valid_arr = [5, 2, 8, 3];
    println!("Max number: {}", max_by_float_or_err(&valid_arr)?); // 输出8

    let invalid_arr = [3, -1, 6];
    assert!(max_by_float_or_err(&invalid_arr).is_err());

    let empty_arr: &[i32] = &[];
    assert!(matches!(max_by_float_or_err(empty_arr), Err(ErrorKind::EmptyArray)));

    Ok(())
}

方案说明

  1. try_fold的优势:Rust标准库的try_fold专门用于带错误的归约操作,闭包返回Result时,一旦出错就会立即停止迭代并向上传播错误,完美匹配需求。
  2. 错误传播逻辑:在闭包内用?处理float_or_err的返回值,出错直接终止流程;try_fold会自动将错误传递到外层。
  3. 最大值比较:借助OrderedFloat实现浮点数的全序比较,每次迭代更新当前的最大值键值对。
  4. 边界处理:最后通过and_then处理空数组的情况,可根据业务需求调整错误类型或返回默认值。

依赖说明

需要在Cargo.toml中添加ordered_float依赖:

[dependencies]
ordered_float = "3.0"

内容的提问来源于stack exchange,提问作者Max

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 11:42:41