Rust - 在 map 闭包中处理 Result

Lobsters Hottest 工具

摘要

本文探讨了在 map 闭包中使用返回 Result 的函数时常见的 Rust 错误,并提供了多种解决方案:收集结果、使用循环、filter_map 和 try_fold。

<p><a href="https://lobste.rs/s/1r09vz/rust_handling_results_map_closure">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/07/04 06:38

# 在 Map 闭包中处理 Result 来源:https://reemus.dev/tldr/rust-handling-results-in-map-closure 你是否遇到过在 Rust 的 `.map()` 闭包中使用返回 `Result` 的函数时报错的问题?我相信这是学习 Rust 时常见的困扰。幸运的是,解决方案其实很简单。 ## 问题 考虑以下 Rust 代码,其中有两个函数都返回 `Result` 类型。第一个函数为一行(字符串切片)添加前缀,第二个函数接受一个行列表并使用第一个函数为每行添加前缀。 ```rust use std::error::Error; fn prefix_line(line: &str) -> Result<String, Box<dyn Error>> { Ok(format!("PREFIX: {}", line)) } fn prefix_each(lines: &[&str]) -> Result<Vec<String>, Box<dyn Error>> { let result = lines .iter() .map(|line| prefix_line(line)?) .collect::<Vec<String>>(); Ok(result) } ``` rust-icon 尝试编译这段代码会在第 10 行出现错误: > the '?' operator can only be used in a closure that returns 'Result' or 'Option' (or another type that implements 'FromResidual') [E0277] > Help: the trait 'FromResidual<Result<Infallible, Box<dyn Error>>>' is not implemented for 'std::string::String' 错误分析: - `map` 函数接受一个闭包作为参数 - `.map()` 闭包中的 `?` 运算符有问题 - 因为 `?` 运算符期望闭包返回 `Result` 或 `Option` - 而闭包的返回类型被推断为与 `map` 期望的输出类型匹配,即 `String` - 由于 `String` 没有实现 `FromResidual`,因此报错 ## 解决方案 ### 收集结果 我发现解决这个问题最简单的方法: - 调用 `prefix_line(line)` 时不使用 `?` 运算符,这会输出 `Vec<Result<String, ...>>` - 使用 `collect::<Result<Vec<_>, _>>()?` 来正确推断类型,收集所有的 `Result` 并在出错时传播错误 - 最终得到我们想要的 `Vec<String>` ```rust fn prefix_each(lines: &[&str]) -> Result<Vec<String>, Box<dyn Error>> { let result = lines .iter() .map(|line| prefix_line(line)) .collect::<Result<Vec<_>, _>>()?; Ok(result) } ``` rust-icon ### 使用循环 显而易见的初始解决方案,但存在缺点: - 打破了函数式风格 - 需要可变变量 ```rust fn prefix_each(lines: &[&str]) -> Result<Vec<String>, Box<dyn Error>> { let mut result = Vec::new(); for line in lines { result.push(prefix_line(line)?); } Ok(result) } ``` rust-icon ### 使用 filter_map - `filter_map` 会丢弃 `Err` 值,只收集成功的 `Ok` 值 - 如果你希望忽略错误,只关心成功的结果,这个方案很有用 ```rust fn prefix_each(lines: &[&str]) -> Result<Vec<String>, Box<dyn Error>> { let result = lines .iter() .filter_map(|line| prefix_line(line).ok()) .collect::<Vec<String>>(); Ok(result) } ``` rust-icon ### 使用 try_fold - 使用 `try_fold` 来聚合结果并优雅地处理错误 - 它允许你直接返回 `Result` 类型 ```rust fn prefix_each(lines: &[&str]) -> Result<String, Box<dyn Error>> { let result = lines.iter().try_fold(String::new(), |mut acc, line| { prefix_line(line).map(|prefixed_line| { acc.push_str(&prefixed_line); acc.push_str("\n"); acc }) })?; Ok(result) } ``` rust-icon

相似文章

Rust错误处理的新视角

Lobsters Hottest

本文讨论了Rust中不同的错误处理模式,包括panic、使用Option和Result、以及默认恢复机制,并提出了一种超越简单传播或恢复的错误处理方法。

Rust 中的进行中工作

Lobsters Hottest

本文介绍了一种在 Rust 开发过程中延迟错误处理的技术和库,允许开发者临时将错误降级为警告,从而在保持正确性的同时维持生产力。

不会编译的数据竞争

Hacker News Top

本文解释了作者如何利用ruxe库中的类型级不相交技术,教会Rust的类型系统拒绝可能导致数据竞争的并行reducer管道。

iddqd:最难的一种不安全Rust

Lobsters Hottest

本文介绍了 iddqd,这是一个 Rust 库,它提供了从值中借用键的映射,减少了重复和同步问题。本文讨论了编写不安全 Rust 代码的挑战以及该库如何保持正确性。