← 返回日报
略读 预计 1 分钟

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)
}
rust-icon

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 map function takes a closure as it's argument

  • The ? operator inside the .map() closure is problematic

  • This is because the ? operator expects the closure to return a Result or Option

  • Instead, the closure's return type is inferred to match the expected output type of map, which is String

  • Since String doesn't implement FromResidual, 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 outputs Vec<Result<...>>

  • Use collect::<Result<Vec<_>, _>>()? to correctly infer types, collect the Results and propagate errors if any

  • Leaving 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)
}
rust-icon

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)
}
rust-icon

Using filter_map

  • filter_map discards Err values collecting only successful Ok values

  • Useful 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)
}
rust-icon

Using try_fold

  • Use try_fold to aggregate results and handle errors gracefully

  • It 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)
}
rust-icon

👍🔥❤️😂😢😕

...

Loading comments...

Lobsters · 1 赞 · 0 评 讨论 → 阅读原文 →

这条对你有帮助吗?