Chuyển đến nội dung chính

レッスン 7: エラー処理とモジュール

結果、オプション、アンラップ、期待。 ?演算子、エラー伝播。カスタム エラー タイプ、thiserror など。モジュールシステム、クレート構造、パブの可視性。貨物作業スペース。

💻 プログラミング — レッスン 7 レッスン 7: エラー処理とモジュール

Rust: 基本から上級まで

パート 2: 高度な Rust

xdev.asia

1. 結果とオプション

use std::fs;
use std::num::ParseIntError;

fn main() {
    // Option<T> — có hoặc không
    let value: Option<i32> = Some(42);
    let nothing: Option<i32> = None;

    // Unwrap — PROD không nên dùng
    let v = value.unwrap();          // panic nếu None
    let v = value.expect("No value"); // panic với message

    // Safe access
    let v = value.unwrap_or(0);
    let v = value.unwrap_or_else(|| compute_default());
    let v = value.map(|x| x * 2);   // Some(84)

    // Result<T, E> — success hoặc error
    let content: Result<String, std::io::Error> = fs::read_to_string("config.toml");
    match content {
        Ok(text) => println!("{}", text),
        Err(e) => eprintln!("Error: {}", e),
    }
}

2.?演算子とエラーの伝播

use std::io;

fn read_config() -> Result<Config, AppError> {
    let content = fs::read_to_string("config.toml")?; // Auto-convert io::Error → AppError
    let port: u16 = content.trim().parse()?;            // Auto-convert ParseIntError → AppError
    Ok(Config { port })
}

// ? hoạt động nhờ From trait
// impl From<io::Error> for AppError { ... }
// impl From<ParseIntError> for AppError { ... }

3. thiserror などのカスタム エラー

// thiserror — cho library code
use thiserror::Error;

#[derive(Error, Debug)]
enum AppError {
    #[error("Database error: {0}")]
    Database(#[from] sqlx::Error),

    #[error("Not found: {entity} with id {id}")]
    NotFound { entity: String, id: String },

    #[error("Unauthorized")]
    Unauthorized,

    #[error("Validation error: {0}")]
    Validation(String),

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

// anyhow — cho application code
use anyhow::{Context, Result};

async fn setup_database() -> Result<Pool<Postgres>> {
    let url = std::env::var("DATABASE_URL")
        .context("DATABASE_URL must be set")?;

    let pool = PgPoolOptions::new()
        .max_connections(5)
        .connect(&url)
        .await
        .context("Failed to connect to database")?;

    Ok(pool)
}

4. モジュールシステム

src/
├── main.rs
├── lib.rs
├── config.rs
├── models/
│   ├── mod.rs
│   ├── user.rs
│   └── product.rs
└── handlers/
    ├── mod.rs
    └── auth.rs
// src/models/mod.rs
pub mod user;
pub mod product;

// src/models/user.rs
pub struct User {
    pub id: u64,
    pub username: String,
    email: String, // private
}

impl User {
    pub fn new(id: u64, username: String, email: String) -> Self {
        Self { id, username, email }
    }
}

// src/main.rs
mod config;
mod models;
mod handlers;

use models::user::User;
# Cargo workspace — multiple crates
# Cargo.toml (root)
[workspace]
members = ["api", "domain", "infrastructure"]

# api/Cargo.toml
[dependencies]
domain = { path = "../domain" }
infrastructure = { path = "../infrastructure" }

次の記事: スマート ポインタと同時実行性。