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:不要 panic

Lobsters Hottest

一段视频转录文本,讨论如何通过使用组合器和 Result 类型而不是 unwrap 来避免 Rust 中的 panic,解释了三种典型的崩溃原因,并强调编写健壮的代码。

Rust错误处理的新视角

Lobsters Hottest

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

Rust 错误处理中缺失的一块

Lobsters Hottest

作者介绍了一个新的 Rust 错误处理库 eros,用元组形式的"错误集合"(开放和类型 ErrorUnion)替代手写枚举,让错误类型像函数一样自由组合,同时保留编译期对可能错误的精确追踪。

捕获子句作为效果

Lobsters Hottest

本文探讨了Rust中显式捕获子句作为move表达式的替代方案,提出了一种将引用转换为所有权值的一等语言特性,并分析了多种闭包捕获模式。