0Pricing
Learn Rust Coding · 课时

anyhow

灵活的应用错误处理

anyhow 是 CoddyKit 上的免费 Learn Rust Coding 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Learn Rust Coding 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Learn Rust Coding 课程共包含 4 节课。

灵活的应用程序错误

在应用程序代码中,您通常只希望错误携带上下文向上传递,而不想为每种错误分别定义带类型的枚举。anyhow 软件包正好为此提供了一个简单的错误类型。

添加 anyhow

将其添加为依赖项。它与 thiserror 配合良好:库使用 thiserror,二进制程序使用 anyhow。

[dependencies]
anyhow = "1.0"

anyhow::Result 别名

anyhow::Result<T> 是 Result<T, anyhow::Error> 的简写。Error 类型可以容纳任何实现了 std::error::Error 的错误。

use anyhow::Result;

fn load() -> Result<String> {
    let text = std::fs::read_to_string("config.txt")?;
    Ok(text)
}

自动转换

? 运算符会自动将任何标准错误转换为 anyhow::Error,因此您可以自由混用不同的错误类型。

use anyhow::Result;

fn parse_file(path: &str) -> Result<i32> {
    let text = std::fs::read_to_string(path)?; // io error
    let n: i32 = text.trim().parse()?;          // parse error
    Ok(n)
}

添加上下文

.context() 方法会为错误附加一条易于理解的消息,在发生失败时构建出清晰的错误链。

use anyhow::{Context, Result};

fn read_config(path: &str) -> Result<String> {
    let text = std::fs::read_to_string(path)
        .context("failed to read config file")?;
    Ok(text)
}

延迟添加上下文

在构建消息的成本较高或需要运行时数据时,请使用 with_context;该闭包只会在发生错误时执行。

use anyhow::{Context, Result};

fn open(path: &str) -> Result<String> {
    std::fs::read_to_string(path)
        .with_context(|| format!("could not open {path}"))
}

创建临时错误

anyhow! 宏会根据消息构建错误,而 bail! 宏会携带该错误提前返回。

use anyhow::{anyhow, bail, Result};

fn check(age: i32) -> Result<()> {
    if age < 0 {
        bail!("age cannot be negative");
    }
    if age > 150 {
        return Err(anyhow!("age {age} is implausible"));
    }
    Ok(())
}

使用 ensure!

ensure! 类似于 assert!,但它会返回错误,而不是触发恐慌。

use anyhow::{ensure, Result};

fn divide(a: i32, b: i32) -> Result<i32> {
    ensure!(b != 0, "division by zero");
    Ok(a / b)
}

main 中的 anyhow

让 main 返回 anyhow::Result<()>,这样发生失败时就会打印格式良好的错误链。

use anyhow::Result;

fn main() -> Result<()> {
    let text = std::fs::read_to_string("data.txt")?;
    println!("{text}");
    Ok(())
}

检查原因

尽管 anyhow::Error 是不透明的,您仍然可以检查它。需要根据具体错误类型进行分支处理时,downcast_ref 可以恢复具体的错误类型。

use anyhow::Result;

fn report(err: anyhow::Error) {
    if let Some(io) = err.downcast_ref::<std::io::Error>() {
        println!("io error: {io}");
    } else {
        println!("other error: {err}");
    }
}

thiserror 与 anyhow

经验法则:

  • thiserror — 用于库,以及调用方需要匹配的带类型错误
  • anyhow — 用于应用程序,只需携带上下文向上传递错误

您可以使用 ?,将 thiserror 错误无缝转换为 anyhow。

快速检查

anyhow 的哪个方法会在错误传播时为其附加描述性消息?

回顾

您已经学习了 anyhow 软件包:

  • anyhow::Result<T> 使用一种灵活的错误类型
  • ? 会自动转换任何标准错误
  • .context() / with_context() 会添加易于理解的消息
  • anyhow!、bail! 和 ensure! 可以创建错误
  • 最适合应用程序(二进制程序)代码

常见问题解答

「anyhow」课时是免费的吗?

是的 — 「anyhow」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Learn Rust Coding 课程的其余内容,请升级到 CoddyKit PRO。 Learn Rust Coding 课程共包含 4 节课。

「anyhow」这节课中我会学到什么?

灵活的应用错误处理 你通过在浏览器中直接运行的动手代码来练习 Learn Rust Coding,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Learn Rust Coding 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Learn Rust Coding 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「anyhow」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Learn Rust Coding 课中编写并运行代码吗?

能。每节 Learn Rust Coding 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. Result 与 ? 运算符
  2. thiserror
  3. anyhow
  4. 错误转换
← 返回 Learn Rust Coding