---
title: Result と Option
url: https://doc.liz6.com/ja/rust/05-error-handling/01-Result-Option
locale: ja
area: rust
tags:
- rust
- error-handling
date: 2026-06-30
modified: 2026-07-16
description: Option は「値が存在しない可能性がある」ことを表し、Result は「操作が失敗する可能性がある」ことを表します。これらは例外ではなく列挙型です。`?` 演算子は None/Err に遭遇すると早期リターンし、combinator チェーン (map/and_then/or_else) により、エラー処理は try-catch による制御フローのジャンプではなく、型安全なパイプラインとなります。
---

# Result と Option

> Option は「値が存在しない可能性がある」ことを表し、Result は「操作が失敗する可能性がある」ことを表します。これらは例外ではなく列挙型です。`?` 演算子は None/Err に遭遇すると早期リターンし、combinator チェーン (map/and_then/or_else) により、エラー処理は try-catch による制御フローのジャンプではなく、型安全なパイプラインとなります。

## Option: 値が存在しない可能性がある

```rust
fn find_user(id: u64) -> Option<User> { ... }

find_user(42)
    .map(|u| u.name)                 // Option<User> → Option<String>、変換
    .and_then(|name| db_lookup(&name)) // Option<String> → Option<Record>、チェーン
    .filter(|r| r.active)            // active のみ保持
    .unwrap_or(default_record);      // 抽出またはデフォルト値を使用
```

各 combinator は `Some` の場合のみ処理し、`None` は自動的にショートサーキットします。このパターンは関数型プログラミングにおいて「レールウェイ指向プログラミング」と呼ばれます。成功の軌道に沿って値を渡すか、失敗の軌道に一瞬でジャンプしてそのままそこに留まり、null チェックは行われません。`unwrap_or` の時点でコンパイラがデフォルト値の提供を強制するため、値の欠落に対する処理を見逃すことはありません。

## Result: エラーは値であり、例外ではない

```rust
fn parse(s: &str) -> Result<i32, ParseIntError> { s.parse() }

let n = match parse("42") {
    Ok(n) => n * 2,
    Err(e) => { eprintln!("parse failed: {}", e); return; }
};
```

例外との核心的な違い：**エラーは戻り値の一部**であり、呼び出し元は関数のシグネチャからそれが失敗する可能性があることを知ることができます。隠れた制御フローはなく、「この関数はどのような例外を投げるか」といったことを覚える必要もありません。コンパイラは `Result` の処理を強制し、`#[must_use]` 属性により未使用の Result に対してコンパイル警告が発生します。

## ? 演算子: エラーの早期リターン

```rust
fn read_config(path: &str) -> Result<Config, Error> {
    let file = std::fs::read_to_string(path)?;    // Err → 早期リターン
    let config: Config = toml::from_str(&file)?;
    Ok(config)
}
```

展開した同等のコードは以下の通りです：

```rust
let file = match std::fs::read_to_string(path) {
    Ok(v) => v,
    Err(e) => return Err(e.into()),  // .into() は From トレイトを通じてエラー型を変換
};
```

`?` は `From::from` を呼び出して自動的なエラー型の変換を行います。`From<io::Error> for MyError` が実装されていれば、`std::fs::read_to_string()?` の `io::Error` は自動的に `MyError` に変換されます。これが Rust におけるエラー伝播の鍵であり、各レイヤーで手動でエラーをラップする必要がありません。

## main で Result を返す

```rust
fn main() -> Result<(), Box<dyn Error>> {
    let config = read_config()?;     // main 内での ?!
    Ok(())
}
```

`main` が `Result` を返す場合、`main` が `Err` を返すと、ランタイムがエラーを出力して終了します（終了コード 1）。これは単純な CLI ツールに適しています。複雑なアプリケーションでは、通常、独自のエラー処理とログ記録が行われます。

## 参考

- **Rust Book**: 第 9 章
- **Rust By Example**: Option/Result, ?

*Keywords: Option, Result, combinator, and_then, ?, error propagation, From trait, #[must_use]*
