第8章: 制御構造

学習目標

  • if文とif式の使い方を理解する
  • ループ(loop、while、for)を使いこなす
  • match式によるパターンマッチングを学ぶ
  • 制御フローの高度なテクニックを把握する

---

8.1 条件分岐

8.1.1 if 式

Rustのifは式(expression)です:

fn main() {
    let number = 3;

    if number < 5 {
        println!("条件は真");
    } else {
        println!("条件は偽");
    }
}

if は式なので値を返せる

fn main() {
    let condition = true;
    let number = if condition { 5 } else { 6 };

    println!("number = {}", number); // 5
}

重要:各アームの型は同じでなければならない

// ❌ コンパイルエラー
let number = if condition { 5 } else { "six" };

// ✅ OK
let number = if condition { 5 } else { 6 };

8.1.2 else if

複数の条件を評価:

fn main() {
    let number = 6;

    if number % 4 == 0 {
        println!("4で割り切れる");
    } else if number % 3 == 0 {
        println!("3で割り切れる");
    } else if number % 2 == 0 {
        println!("2で割り切れる");
    } else {
        println!("4、3、2のいずれでも割り切れない");
    }
}

パフォーマンス

  • 条件は上から順に評価される
  • 最初に真になった条件のみ実行
  • 多くの条件がある場合はmatchの使用を検討

8.1.3 let if パターン

変数初期化での使用:

fn main() {
    let is_even = true;

    let result = if is_even {
        "偶数"
    } else {
        "奇数"
    };

    println!("{}", result);
}

---

8.2 ループ

8.2.1 loop - 無限ループ

loopキーワードは無限ループを作成します:

fn main() {
    let mut count = 0;

    loop {
        count += 1;
        println!("count = {}", count);

        if count == 5 {
            break;
        }
    }
}

loopから値を返す

fn main() {
    let mut counter = 0;

    let result = loop {
        counter += 1;

        if counter == 10 {
            break counter * 2;
        }
    };

    println!("結果: {}", result); // 20
}

ループラベル

fn main() {
    let mut count = 0;

    'outer: loop {
        println!("count = {}", count);
        let mut remaining = 10;

        loop {
            println!("remaining = {}", remaining);

            if remaining == 9 {
                break;
            }

            if count == 2 {
                break 'outer;
            }

            remaining -= 1;
        }

        count += 1;
    }

    println!("終了: count = {}", count);
}

8.2.2 while - 条件付きループ

条件が真の間ループ:

fn main() {
    let mut number = 3;

    while number != 0 {
        println!("{}!", number);
        number -= 1;
    }

    println!("発射!");
}

配列の走査(非推奨)

fn main() {
    let a = [10, 20, 30, 40, 50];
    let mut index = 0;

    while index < 5 {
        println!("値: {}", a[index]);
        index += 1;
    }
}

問題点

  • インデックスミスでパニックの可能性
  • 遅い(境界チェックが毎回必要)
  • 8.2.3 for - コレクションのループ

    最も安全で推奨される方法:

    fn main() {
        let a = [10, 20, 30, 40, 50];
    
        for element in a {
            println!("値: {}", element);
        }
    }
    

    範囲を使う

    fn main() {
        // 0..5 は 0, 1, 2, 3, 4
        for number in 0..5 {
            println!("{}", number);
        }
    
        // 0..=5 は 0, 1, 2, 3, 4, 5
        for number in 0..=5 {
            println!("{}", number);
        }
    
        // 逆順
        for number in (1..=5).rev() {
            println!("{}!", number);
        }
        println!("発射!");
    }
    

    イテレータメソッド

    fn main() {
        let v = vec![1, 2, 3, 4, 5];
    
        // インデックス付き
        for (index, value) in v.iter().enumerate() {
            println!("{}: {}", index, value);
        }
    
        // 可変参照
        let mut v = vec![1, 2, 3];
        for item in &mut v {
            *item *= 2;
        }
        println!("{:?}", v); // [2, 4, 6]
    }
    

    ---

    8.3 match式

    8.3.1 基本的なmatch

    最も強力なパターンマッチング:

    fn main() {
        let number = 3;
    
        match number {
            1 => println!("一"),
            2 => println!("二"),
            3 => println!("三"),
            _ => println!("その他"),
        }
    }
    

    matchは式

    fn main() {
        let number = 3;
    
        let result = match number {
            1 => "一",
            2 => "二",
            3 => "三",
            _ => "その他",
        };
    
        println!("{}", result);
    }
    

    複数行の処理

    fn main() {
        let number = 5;
    
        match number {
            1 => {
                println!("一です");
                println!("追加の処理");
            }
            2 | 3 => println!("二か三"),
            4..=6 => println!("4から6"),
            _ => println!("その他"),
        }
    }
    

    8.3.2 パターンの種類

    リテラル

    let x = 1;
    
    match x {
        1 => println!("one"),
        2 => println!("two"),
        _ => println!("other"),
    }
    

    範囲

    let x = 5;
    
    match x {
        1..=5 => println!("1から5"),
        6..=10 => println!("6から10"),
        _ => println!("その他"),
    }
    

    複数パターン

    let x = 2;
    
    match x {
        1 | 2 => println!("1か2"),
        3 | 4 => println!("3か4"),
        _ => println!("その他"),
    }
    

    8.3.3 値の分配

    タプル

    fn main() {
        let pair = (0, -2);
    
        match pair {
            (0, y) => println!("x=0, y={}", y),
            (x, 0) => println!("x={}, y=0", x),
            _ => println!("どちらでもない"),
        }
    }
    

    構造体

    struct Point {
        x: i32,
        y: i32,
    }
    
    fn main() {
        let point = Point { x: 0, y: 7 };
    
        match point {
            Point { x: 0, y } => println!("y軸上: y={}", y),
            Point { x, y: 0 } => println!("x軸上: x={}", x),
            Point { x, y } => println!("それ以外: ({}, {})", x, y),
        }
    }
    

    列挙型

    enum Message {
        Quit,
        Move { x: i32, y: i32 },
        Write(String),
        ChangeColor(i32, i32, i32),
    }
    
    fn main() {
        let msg = Message::Move { x: 10, y: 20 };
    
        match msg {
            Message::Quit => println!("終了"),
            Message::Move { x, y } => println!("移動: ({}, {})", x, y),
            Message::Write(text) => println!("テキスト: {}", text),
            Message::ChangeColor(r, g, b) => println!("色: ({}, {}, {})", r, g, b),
        }
    }
    

    8.3.4 ガード

    追加の条件を指定:

    fn main() {
        let number = 4;
    
        match number {
            x if x < 5 => println!("5未満: {}", x),
            x if x % 2 == 0 => println!("偶数: {}", x),
            x => println!("その他: {}", x),
        }
    }
    

    複雑な条件

    fn main() {
        let pair = (2, -2);
    
        match pair {
            (x, y) if x == y => println!("同じ値"),
            (x, y) if x + y == 0 => println!("合計が0"),
            (x, _) if x % 2 == 0 => println!("xは偶数"),
            _ => println!("その他"),
        }
    }
    

    8.3.5 @ バインディング

    パターンマッチしながら値を束縛:

    fn main() {
        let number = 5;
    
        match number {
            n @ 1..=5 => println!("{}は1から5", n),
            n @ 6..=10 => println!("{}は6から10", n),
            _ => println!("その他"),
        }
    }
    

    ---

    8.4 if let と while let

    8.4.1 if let

    単一のパターンマッチングを簡潔に:

    fn main() {
        let some_value = Some(3);
    
        // match版
        match some_value {
            Some(3) => println!("three"),
            _ => (),
        }
    
        // if let版(より簡潔)
        if let Some(3) = some_value {
            println!("three");
        }
    }
    

    else節

    fn main() {
        let some_value = Some(5);
    
        if let Some(3) = some_value {
            println!("three");
        } else {
            println!("not three");
        }
    }
    

    8.4.2 while let

    パターンマッチしながらループ:

    fn main() {
        let mut stack = Vec::new();
    
        stack.push(1);
        stack.push(2);
        stack.push(3);
    
        // pop()がSome(value)を返す間ループ
        while let Some(top) = stack.pop() {
            println!("{}", top);
        }
    }
    

    Vec のイテレーション

    fn main() {
        let v = vec![1, 2, 3];
        let mut iter = v.iter();
    
        while let Some(value) = iter.next() {
            println!("{}", value);
        }
    }
    

    ---

    8.5 制御フローの比較

    ┌─────────────────────────────────────────────────────────┐
    │           制御構造の使い分け                             │
    ├─────────────────────────────────────────────────────────┤
    │                                                         │
    │  if                                                     │
    │  - 単純な条件分岐                                       │
    │  - 2-3個の条件                                          │
    │                                                         │
    │  match                                                  │
    │  - 複数のパターンマッチ                                 │
    │  - 網羅性チェックが必要                                 │
    │  - 列挙型の処理                                         │
    │                                                         │
    │  if let                                                 │
    │  - 単一パターンマッチ                                   │
    │  - Option/Resultの簡潔な処理                            │
    │                                                         │
    │  loop                                                   │
    │  - 無限ループ                                           │
    │  - 明示的なbreak                                        │
    │                                                         │
    │  while                                                  │
    │  - 条件付きループ                                       │
    │                                                         │
    │  for                                                    │
    │  - コレクションの走査                                   │
    │  - 範囲の反復                                           │
    │                                                         │
    └─────────────────────────────────────────────────────────┘
    

    ---

    8.6 実践例

    例1:FizzBuzz

    fn fizzbuzz(n: i32) {
        for i in 1..=n {
            match (i % 3, i % 5) {
                (0, 0) => println!("FizzBuzz"),
                (0, _) => println!("Fizz"),
                (_, 0) => println!("Buzz"),
                _ => println!("{}", i),
            }
        }
    }
    
    fn main() {
        fizzbuzz(15);
    }
    

    例2:コマンドパーサー

    enum Command {
        Start,
        Stop,
        Restart,
        Status,
    }
    
    fn parse_command(input: &str) -> Option<Command> {
        match input.trim().to_lowercase().as_str() {
            "start" => Some(Command::Start),
            "stop" => Some(Command::Stop),
            "restart" => Some(Command::Restart),
            "status" => Some(Command::Status),
            _ => None,
        }
    }
    
    fn handle_command(cmd: Command) {
        match cmd {
            Command::Start => println!("サービスを開始します"),
            Command::Stop => println!("サービスを停止します"),
            Command::Restart => println!("サービスを再起動します"),
            Command::Status => println!("サービスの状態を確認します"),
        }
    }
    
    fn main() {
        if let Some(cmd) = parse_command("start") {
            handle_command(cmd);
        } else {
            println!("不明なコマンド");
        }
    }
    

    例3:状態機械

    enum State {
        Idle,
        Running,
        Paused,
        Stopped,
    }
    
    enum Event {
        Start,
        Pause,
        Resume,
        Stop,
    }
    
    fn next_state(state: State, event: Event) -> State {
        match (state, event) {
            (State::Idle, Event::Start) => State::Running,
            (State::Running, Event::Pause) => State::Paused,
            (State::Paused, Event::Resume) => State::Running,
            (State::Running, Event::Stop) => State::Stopped,
            (State::Paused, Event::Stop) => State::Stopped,
            (s, _) => s, // その他は状態変化なし
        }
    }
    
    fn main() {
        let mut state = State::Idle;
    
        state = next_state(state, Event::Start);
        println!("実行中");
    
        state = next_state(state, Event::Pause);
        println!("一時停止");
    
        state = next_state(state, Event::Resume);
        println!("再開");
    
        state = next_state(state, Event::Stop);
        println!("停止");
    }
    

    例4:計算機

    fn calculate(operator: char, a: f64, b: f64) -> Option<f64> {
        match operator {
            '+' => Some(a + b),
            '-' => Some(a - b),
            '*' => Some(a * b),
            '/' if b != 0.0 => Some(a / b),
            '/' => None, // ゼロ除算
            _ => None,   // 不明な演算子
        }
    }
    
    fn main() {
        let operations = vec![
            ('+', 5.0, 3.0),
            ('-', 5.0, 3.0),
            ('*', 5.0, 3.0),
            ('/', 5.0, 0.0),
        ];
    
        for (op, a, b) in operations {
            match calculate(op, a, b) {
                Some(result) => println!("{} {} {} = {}", a, op, b, result),
                None => println!("{} {} {} : エラー", a, op, b),
            }
        }
    }
    

    ---

    8.7 パフォーマンスの考慮

    8.7.1 ループの最適化

    // ❌ 遅い:境界チェックが毎回
    let mut sum = 0;
    let mut i = 0;
    while i < arr.len() {
        sum += arr[i];
        i += 1;
    }
    
    // ✅ 速い:イテレータ使用
    let sum: i32 = arr.iter().sum();
    
    // ✅ 速い:forループ
    let mut sum = 0;
    for &item in &arr {
        sum += item;
    }
    

    8.7.2 matchの最適化

    コンパイラはmatchを最適化します:

    // ジャンプテーブルに最適化される可能性
    match value {
        0 => handle_zero(),
        1 => handle_one(),
        2 => handle_two(),
        // ...
        _ => handle_default(),
    }
    

    ---

    8.8 まとめ

    学んだこと

  • 条件分岐
- if式と値の返却 - else if による複数条件

  • ループ
- loop:無限ループ - while:条件付きループ - for:コレクションの走査

  • match式
- パターンマッチング - 値の分配 - ガード条件

  • 簡潔な構文
- if let - while let

次のステップ

次の章では、関数とクロージャを学びます: