Rust - Handling Results In A Map Closure
摘要
文章标题为 Rust - Handling Results In A Map Closure,指出读者在使用返回 Result 的函数于 .map() 闭包时遇到的编译错误。该错误源于 ? 运算符要求闭包返回 Result 或 Option,但 .map() 闭包推断类型为 String,导致 String 无法实现 FromResidual。作者列出多种解决方案:最简单的是直接调用 prefix_line (line) 获取 Vec<Result> 后用 collect::<Result <Vec<String>,_>>()? 聚合并传播错误;使用 for 循环(但会打破函数式风格并需可变变量);filter_map 仅保留 Ok 值并丢弃 Err;try fold 则直接返回 Result 类型进行聚合。所有方案均基于正文摘录内容,未添加额外结论或细节。
荐读理由
使用 try fold 来聚合结果并优雅处理错误,可直接迁移到 AI 工程项目里
原文
Rust - Handling Results In A Map Closure
👍🔥❤️😂😢😕
views
Are you encountering an error when trying to use a function that returns a Result within a .map() closure in Rust? I'm sure this is a common problem people face when learning to use Rust. Thankfully, the solution is actually quite simple.
Problem
Consider the following Rust code where we have two functions, both returning Result types. The first function prefixes a line (a string slice), and the second function takes a list of lines and prefixes each using the first function.
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<_>>();
Ok(result)
}
Attempting to compile this code results in an error on line 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>>' is not implemented for 'std::string::String'
Breaking down the error:
The
mapfunction takes a closure as it's argumentThe
?operator inside the.map()closure is problematicThis is because the
?operator expects the closure to return aResultorOptionInstead, the closure's return type is inferred to match the expected output type of map, which is
StringSince
Stringdoesn't implementFromResidual, you get the error
Solutions
Collect the results
The simplest way I've found to solve this issue:
Call
prefix_line(line)without the?operator which outputsVec<Result<...>>Use
collect::<Result<Vec<_>, _>>()?to correctly infer types, collect theResultsand propagate errors if anyLeaving us with our desired output
Vec<String>
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)
}
Using a loop
The obvious initial solution but it has drawbacks such as:
It breaks the functional style
It requires a mutable variable
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)
}
Using filter_map
filter_mapdiscardsErrvalues collecting only successfulOkvaluesUseful if you want to ignore errors and only care about the successful results
fn prefix_each(lines: &[&str]) -> Result<Vec<String>, Box<dyn Error>> {
let result = lines
.iter()
.filter_map(|line| prefix_line(line).ok())
.collect::<Vec<_>>();
Ok(result)
}
Using try_fold
Use
try_foldto aggregate results and handle errors gracefullyIt allows you to return a Result type directly
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)
}
👍🔥❤️😂😢😕
...
Loading comments...
这条对你有帮助吗?