Rust错误处理

Mattakushi4322026-10-26查看 1900复制 615

何时激活:Rust 错误处理、thiserror、无论如何、自定义错误、结果、问号运算符、错误传播

Download (.md)

📘如何使用这个技能

  1. 1
    复制技能内容·点击上方「Copy SKILL.md」复制全部内容,或 Download 下载到本地
  2. 2
    打开你的 AI 客户端·支持 Claude Code、Trae、Cursor、ChatGPT、DeepSeek、Kimi 等任意 AI 助手
  3. 3
    粘贴为系统提示/知识文件·Claude Code:放入 .claude/skills/ 目录;普通对话:作为首条消息发送并说「请严格按这份技能文档执行」
  4. 4
    直接提出你的需求·AI 会按技能定义的工作流、格式和约束来处理,无需再解释背景

💡 提示:技能生效后,每次对话只需一句需求,AI 会按 SKILL.md 的流程执行。

SKILL.md3867 chars
---
name: rust-error-handling
description: "When to activate: Rust error handling, thiserror, anyhow, custom errors, Result, question mark operator, error propagation"
origin: zakr
metadata:
  namespace: zakr/devtools-pack
  version: 1.0.0
  category: engineering
  language: rust
  platforms: [claude-code, codex, gemini-cli, cursor, aider, windsurf]
---

# Rust Error Handling

## Custom Errors with thiserror

`thiserror` generates `Display` and `Error` impls from derive macros.

```toml
[dependencies]
thiserror = "2"
```

```rust
use thiserror::Error;

#[derive(Debug, Error)]
pub enum AppError {
    #[error("user {id} not found")]
    UserNotFound { id: u64 },

    #[error("database error: {0}")]
    Database(#[from] sqlx::Error),

    #[error("validation failed on field '{field}': {message}")]
    Validation { field: String, message: String },

    #[error("external service '{service}' returned {status}")]
    ExternalService { service: String, status: u16 },

    #[error(transparent)]
    Unexpected(#[from] anyhow::Error),
}
```

## Application Errors with anyhow

`anyhow` is ideal for application code where you need rich context but don't care about the exact type.

```toml
[dependencies]
anyhow = "1"
```

```rust
use anyhow::{Context, Result, bail, ensure};

fn load_config(path: &str) -> Result<Config> {
    let content = std::fs::read_to_string(path)
        .with_context(|| format!("failed to read config from {path}"))?;

    let config: Config = toml::from_str(&content)
        .context("failed to parse config as TOML")?;

    ensure!(config.port > 1024, "port must be > 1024, got {}", config.port);

    if config.workers == 0 {
        bail!("workers must be at least 1");
    }

    Ok(config)
}
```

## The ? Operator

`?` returns early on error, applying `From` conversion if needed.

```rust
fn process() -> Result<Output, AppError> {
    let data = read_file("input.txt")?;
    let parsed = parse_json(&data)?;
    let result = transform(parsed)?;
    Ok(result)
}

// ? works with Option via .ok_or / .ok_or_else
fn find_setting(name: &str) -> Result<String, AppError> {
    settings()
        .get(name)
        .cloned()
        .ok_or_else(|| AppError::Validation {
            field: name.to_string(),
            message: "setting not found".into(),
        })
}
```

## Error Hierarchy (Library vs. Application)

```rust
// Library crates: use thiserror for typed, structured errors
#[derive(Debug, thiserror::Error)]
pub enum MyLibError {
    #[error("invalid input: {0}")]
    InvalidInput(String),
    #[error(transparent)]
    Io(#[from] std::io::Error),
}

// Application code: use anyhow for ergonomic context chains
fn run() -> anyhow::Result<()> {
    my_lib::process("data.txt")
        .context("processing step failed")?;
    Ok(())
}
```

## Converting Between Error Types

```rust
// map_err for targeted conversion
fn parse_id(s: &str) -> Result<u64, AppError> {
    s.parse::<u64>().map_err(|e| AppError::Validation {
        field: "id".into(),
        message: e.to_string(),
    })
}
```

## Error Handling in Main

```rust
fn main() -> anyhow::Result<()> {
    let config = load_config("config.toml")?;
    run(config)?;
    Ok(())
}

// With custom exit codes
fn main() {
    if let Err(e) = run() {
        eprintln!("Error: {e:#}"); // {:#} prints the full error chain
        std::process::exit(1);
    }
}
```

## Common Anti-Patterns

- **Using `Box<dyn Error>` in library APIs** — prevents callers from matching on specific errors
- **`unwrap()` / `expect()` in production code** — always propagate or handle errors explicitly
- **Losing error context with bare `?`** — use `.context()` from `anyhow` to add what operation failed
- **Returning `String` as error type** — hard for callers to programmatically handle
- **Swallowing errors in closures** — log or propagate; never silently discard
来源:skillsdirectory

评论0

登录后参与评论

还没有评论,来抢沙发吧