switch语句 #

一、switch 基础 #

1.1 基本 switch 语句 #

zig
const std = @import("std");

pub fn main() void {
    const day: u8 = 3;
    
    switch (day) {
        1 => std.debug.print("Monday\n", .{}),
        2 => std.debug.print("Tuesday\n", .{}),
        3 => std.debug.print("Wednesday\n", .{}),
        4 => std.debug.print("Thursday\n", .{}),
        5 => std.debug.print("Friday\n", .{}),
        6, 7 => std.debug.print("Weekend\n", .{}),
        else => std.debug.print("Invalid day\n", .{}),
    }
}

1.2 switch 表达式 #

switch 是表达式,可以返回值:

zig
const std = @import("std");

pub fn main() void {
    const day: u8 = 3;
    
    const day_name = switch (day) {
        1 => "Monday",
        2 => "Tuesday",
        3 => "Wednesday",
        4 => "Thursday",
        5 => "Friday",
        6, 7 => "Weekend",
        else => "Invalid",
    };
    
    std.debug.print("Day: {s}\n", .{day_name});
}

1.3 必须穷尽所有情况 #

zig
const std = @import("std");

pub fn main() void {
    const value: u8 = 5;
    
    // 编译错误:没有处理所有情况
    // switch (value) {
    //     1 => std.debug.print("One\n", .{}),
    //     2 => std.debug.print("Two\n", .{}),
    // }
    
    // 正确:使用 else 处理剩余情况
    switch (value) {
        1 => std.debug.print("One\n", .{}),
        2 => std.debug.print("Two\n", .{}),
        else => std.debug.print("Other\n", .{}),
    }
}

二、模式匹配 #

2.1 多值匹配 #

zig
const std = @import("std");

pub fn main() void {
    const c: u8 = 'a';
    
    switch (c) {
        'a', 'e', 'i', 'o', 'u' => std.debug.print("Vowel\n", .{}),
        'A', 'E', 'I', 'O', 'U' => std.debug.print("Uppercase vowel\n", .{}),
        '0'...'9' => std.debug.print("Digit\n", .{}),
        else => std.debug.print("Other\n", .{}),
    }
}

2.2 范围匹配 #

zig
const std = @import("std");

pub fn main() void {
    const score: i32 = 85;
    
    const grade = switch (score) {
        90...100 => 'A',
        80...89 => 'B',
        70...79 => 'C',
        60...69 => 'D',
        0...59 => 'F',
        else => '?',
    };
    
    std.debug.print("Grade: {c}\n", .{grade});
}

2.3 捕获值 #

zig
const std = @import("std");

pub fn main() void {
    const value: u8 = 5;
    
    switch (value) {
        0 => std.debug.print("Zero\n", .{}),
        1...10 => |v| std.debug.print("Small: {}\n", .{v}),
        11...100 => |v| std.debug.print("Medium: {}\n", .{v}),
        else => |v| std.debug.print("Large: {}\n", .{v}),
    }
}

三、枚举匹配 #

3.1 枚举 switch #

zig
const std = @import("std");

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

pub fn main() void {
    const color = Color.green;
    
    const hex = switch (color) {
        .red => "#FF0000",
        .green => "#00FF00",
        .blue => "#0000FF",
    };
    
    std.debug.print("Color hex: {s}\n", .{hex});
}

3.2 枚举捕获 #

zig
const std = @import("std");

const Direction = enum {
    north,
    south,
    east,
    west,
};

fn getOpposite(dir: Direction) Direction {
    return switch (dir) {
        .north => .south,
        .south => .north,
        .east => .west,
        .west => .east,
    };
}

pub fn main() void {
    const dir = Direction.north;
    const opposite = getOpposite(dir);
    
    std.debug.print("Original: {}, Opposite: {}\n", .{ dir, opposite });
}

3.3 带数据的枚举 #

zig
const std = @import("std");

const Value = union(enum) {
    int: i32,
    float: f64,
    string: []const u8,
};

pub fn main() void {
    const v = Value{ .int = 42 };
    
    switch (v) {
        .int => |i| std.debug.print("Integer: {}\n", .{i}),
        .float => |f| std.debug.print("Float: {d}\n", .{f}),
        .string => |s| std.debug.print("String: {s}\n", .{s}),
    }
}

3.4 修改捕获值 #

zig
const std = @import("std");

const Value = union(enum) {
    int: i32,
    float: f64,
};

pub fn main() void {
    var v = Value{ .int = 42 };
    
    switch (v) {
        .int => |*i| {
            i.* *= 2;
            std.debug.print("Doubled: {}\n", .{i.*});
        },
        .float => |*f| {
            f.* *= 2.0;
            std.debug.print("Doubled: {d}\n", .{f.*});
        },
    }
}

四、标签枚举 #

4.1 使用 else 捕获标签 #

zig
const std = @import("std");

const Status = enum {
    pending,
    approved,
    rejected,
    cancelled,
};

pub fn main() void {
    const status = Status.pending;
    
    switch (status) {
        .approved => std.debug.print("Approved!\n", .{}),
        .rejected => std.debug.print("Rejected\n", .{}),
        else => |s| std.debug.print("Status: {}\n", .{s}),
    }
}

4.2 内联 switch #

zig
const std = @import("std");

pub fn main() void {
    const values = [_]i32{ 1, 2, 3, 4, 5 };
    
    for (values) |v| {
        const result = switch (v) {
            1 => "one",
            2 => "two",
            3 => "three",
            else => "other",
        };
        std.debug.print("{} => {s}\n", .{ v, result });
    }
}

五、高级用法 #

5.1 嵌套 switch #

zig
const std = @import("std");

const Opcode = enum {
    add,
    sub,
    mul,
};

const Mode = enum {
    immediate,
    register,
};

pub fn main() void {
    const opcode = Opcode.add;
    const mode = Mode.immediate;
    
    switch (opcode) {
        .add => {
            switch (mode) {
                .immediate => std.debug.print("ADD immediate\n", .{}),
                .register => std.debug.print("ADD register\n", .{}),
            }
        },
        .sub => {
            switch (mode) {
                .immediate => std.debug.print("SUB immediate\n", .{}),
                .register => std.debug.print("SUB register\n", .{}),
            }
        },
        .mul => {
            switch (mode) {
                .immediate => std.debug.print("MUL immediate\n", .{}),
                .register => std.debug.print("MUL register\n", .{}),
            }
        },
    }
}

5.2 switch 与错误 #

zig
const std = @import("std");

const FileError = error{
    NotFound,
    PermissionDenied,
    TooLarge,
};

pub fn main() void {
    const err = FileError.PermissionDenied;
    
    const message = switch (err) {
        error.NotFound => "File not found",
        error.PermissionDenied => "Permission denied",
        error.TooLarge => "File too large",
    };
    
    std.debug.print("Error: {s}\n", .{message});
}

5.3 switch 与可选类型 #

zig
const std = @import("std");

pub fn main() void {
    const maybe_value: ?i32 = 42;
    
    const result = switch (maybe_value) {
        null => "No value",
        else => |v| blk: {
            break :blk if (v > 10) "Large" else "Small";
        },
    };
    
    std.debug.print("Result: {s}\n", .{result});
}

六、实战示例 #

6.1 简单计算器 #

zig
const std = @import("std");

const Operator = enum {
    add,
    sub,
    mul,
    div,
};

fn calculate(a: f64, op: Operator, b: f64) ?f64 {
    return switch (op) {
        .add => a + b,
        .sub => a - b,
        .mul => a * b,
        .div => if (b != 0) a / b else null,
    };
}

pub fn main() void {
    const operations = [_]struct { f64, Operator, f64 }{
        .{ 10, .add, 5 },
        .{ 10, .sub, 3 },
        .{ 10, .mul, 2 },
        .{ 10, .div, 0 },
    };
    
    for (operations) |op| {
        const a, const operator, const b = op;
        if (calculate(a, operator, b)) |result| {
            std.debug.print("{d} {} {d} = {d}\n", .{ a, operator, b, result });
        } else {
            std.debug.print("{d} {} {d} = Error\n", .{ a, operator, b });
        }
    }
}

6.2 状态机 #

zig
const std = @import("std");

const State = enum {
    idle,
    loading,
    success,
    error,
};

const Event = enum {
    start,
    complete,
    fail,
    reset,
};

fn transition(state: State, event: Event) State {
    return switch (state) {
        .idle => switch (event) {
            .start => .loading,
            else => .idle,
        },
        .loading => switch (event) {
            .complete => .success,
            .fail => .error,
            else => .loading,
        },
        .success => switch (event) {
            .reset => .idle,
            else => .success,
        },
        .error => switch (event) {
            .reset => .idle,
            else => .error,
        },
    };
}

pub fn main() void {
    var state: State = .idle;
    
    state = transition(state, .start);
    std.debug.print("State: {}\n", .{state});
    
    state = transition(state, .complete);
    std.debug.print("State: {}\n", .{state});
    
    state = transition(state, .reset);
    std.debug.print("State: {}\n", .{state});
}

6.3 JSON 值处理 #

zig
const std = @import("std");

const JsonValue = union(enum) {
    null: void,
    bool: bool,
    int: i64,
    float: f64,
    string: []const u8,
    array: []const JsonValue,
};

fn printJson(value: JsonValue, indent: usize) void {
    const spaces = " " ** indent;
    
    switch (value) {
        .null => std.debug.print("{s}null\n", .{spaces}),
        .bool => |b| std.debug.print("{s}{}\n", .{ spaces, b }),
        .int => |i| std.debug.print("{s}{}\n", .{ spaces, i }),
        .float => |f| std.debug.print("{s}{d}\n", .{ spaces, f }),
        .string => |s| std.debug.print("{s}\"{s}\"\n", .{ spaces, s }),
        .array => |arr| {
            std.debug.print("{s}[\n", .{spaces});
            for (arr) |item| {
                printJson(item, indent + 2);
            }
            std.debug.print("{s}]\n", .{spaces});
        },
    }
}

pub fn main() void {
    const json = JsonValue{ .array = &[_]JsonValue{
        .{ .int = 1 },
        .{ .string = "hello" },
        .{ .bool = true },
    } };
    
    printJson(json, 0);
}

七、最佳实践 #

7.1 使用枚举而非魔法数字 #

zig
// 好
const Status = enum {
    pending,
    running,
    completed,
    failed,
};

fn handleStatus(status: Status) void {
    switch (status) {
        .pending => {},
        .running => {},
        .completed => {},
        .failed => {},
    }
}

// 避免
fn handleStatusCode(code: u8) void {
    switch (code) {
        0 => {},
        1 => {},
        2 => {},
        3 => {},
        else => {},
    }
}

7.2 避免空的 else #

zig
// 好:明确处理每种情况
switch (status) {
    .pending => handlePending(),
    .running => handleRunning(),
    .completed => handleCompleted(),
    .failed => handleFailed(),
}

// 避免:空的 else
switch (status) {
    .pending => handlePending(),
    else => {},  // 可能遗漏重要情况
}

7.3 使用 switch 表达式 #

zig
// 好
const message = switch (status) {
    .success => "Operation succeeded",
    .failure => "Operation failed",
};

// 避免
var message: []const u8 = undefined;
switch (status) {
    .success => message = "Operation succeeded",
    .failure => message = "Operation failed",
}

八、总结 #

switch 语句要点:

特性 说明
基本语法 switch (value) { ... }
多值匹配 1, 2, 3 =>
范围匹配 1...10 =>
枚举匹配 .value =>
值捕获 |v| =>
表达式 可返回值

下一步,让我们学习循环语句!

最后更新:2026-03-27