解答5: 制御フローの完全理解

概要

この解答では、Zigの制御フロー構文について学びます。if式、switch式、while/forループを実践的に理解します。

Part 1: if式

const std = @import("std");

pub fn ifExpressionDemo() void {
    const x: i32 = 10;
    
    // if は式として値を返せる
    const description = if (x > 0) "positive" else if (x < 0) "negative" else "zero";
    std.debug.print("Number is: {s}\n", .{description});

    // オプショナルのアンラップ
    const maybe_val: ?i32 = 42;
    if (maybe_val) |val| {
        std.debug.print("Value: {}\n", .{val});
    }
}

Part 2: switch式

const std = @import("std");

const Color = enum { red, green, blue };

fn colorToRgb(color: Color) struct { r: u8, g: u8, b: u8 } {
    return switch (color) {
        .red => .{ .r = 255, .g = 0, .b = 0 },
        .green => .{ .r = 0, .g = 255, .b = 0 },
        .blue => .{ .r = 0, .g = 0, .b = 255 },
    };
}

fn classifyChar(c: u8) []const u8 {
    return switch (c) {
        'a'...'z' => "lowercase",
        'A'...'Z' => "uppercase",
        '0'...'9' => "digit",
        else => "other",
    };
}

Part 3: ループ

const std = @import("std");

pub fn loopDemo() void {
    // while ループ
    var i: u32 = 0;
    while (i < 5) : (i += 1) {
        std.debug.print("i = {}\n", .{i});
    }

    // for ループ
    const items = [_]i32{ 10, 20, 30 };
    for (items, 0..) |item, idx| {
        std.debug.print("items[{}] = {}\n", .{idx, item});
    }

    // ラベル付きブレーク
    const result = blk: {
        var sum: i32 = 0;
        for (0..10) |n| {
            sum += @intCast(n);
            if (sum > 20) break :blk sum;
        }
        break :blk sum;
    };
    std.debug.print("Result: {}\n", .{result});
}

ポイント解説

  • 式としての構文: if、switch、whileは値を返せる
  • キャプチャ構文: オプショナルやエラーをパターンマッチで取り出せる
  • 網羅性チェック: switchは全ケースをカバーする必要がある
  • よくある間違い

    // 無限ループ!i += 1 を忘れている
    var i: u32 = 0;
    while (i < 10) {
        // i += 1; が必要
    }
    
    // 正しい形式
    while (i < 10) : (i += 1) {
        // 処理
    }
    

    自己確認チェックリスト

  • [ ] if式で値を返す方法を理解しているか
  • [ ] switchの網羅性要件を説明できるか
  • [ ] ラベル付きbreak/continueを使えるか