Zig的枚举是真正的类型安全枚举,不像C的枚举只是整数别名:
const std = @import("std");
// 基本枚举
const Direction = enum {
north,
south,
east,
west,
};
// 指定底层整数类型
const HttpStatus = enum(u16) {
ok = 200,
not_found = 404,
server_error = 500,
};
// 枚举可以拥有方法
const Color = enum {
red,
green,
blue,
pub fn toRgb(self: Color) u24 {
return switch (self) {
.red => 0xFF0000,
.green => 0x00FF00,
.blue => 0x0000FF,
};
}
pub fn name(self: Color) []const u8 {
return switch (self) {
.red => "red",
.green => "green",
.blue => "blue",
};
}
};
pub fn main() !void {
const d = Direction.north;
// 获取枚举的整数值
const status = HttpStatus.ok;
const code: u16 = @intFromEnum(status); // 200
// 从整数创建枚举(可能失败)
const maybe_status = std.meta.intToEnum(HttpStatus, 404);
if (maybe_status) |s| {
std.debug.print("status: {}\n", .{s});
} else {
std.debug.print("invalid status\n", .{});
}
// 获取枚举字段名
const name = @tagName(d); // "north"
// 枚举方法
const c = Color.red;
std.debug.print("{} rgb={x}\n", .{ c.name(), c.toRgb() });
_ = code;
_ = name;
}
标签联合体(tagged union)是Zig最强大的类型之一——一个值可以是多种类型之一,编译器确保安全访问:
const std = @import("std");
// 标签联合体:值只能是其中一种
const Value = union(enum) {
int: i64,
float: f64,
string: []const u8,
boolean: bool,
null_val: void,
// 标签联合体可以有方法
pub fn format(self: Value, writer: anytype) !void {
switch (self) {
.int => |n| try writer.print("{}", .{n}),
.float => |f| try writer.print("{d}", .{f}),
.string => |s| try writer.print(\"{s}\"", .{s}),
.boolean => |b| try writer.print("{}", .{b}),
.null_val => try writer.writeAll("null"),
}
}
// 安全的类型检查
pub fn asInt(self: Value) ?i64 {
return switch (self) {
.int => |n| n,
else => null,
};
}
};
// AST节点——标签联合体的经典应用
const Expr = union(enum) {
number: f64,
add: struct { left: *Expr, right: *Expr },
multiply: struct { left: *Expr, right: *Expr },
negate: *Expr,
pub fn eval(self: *const Expr) f64 {
return switch (self.*) {
.number => |n| n,
.add => |op| op.left.eval() + op.right.eval(),
.multiply => |op| op.left.eval() * op.right.eval(),
.negate => |expr| -expr.eval(),
};
}
};
pub fn main() !void {
var values = [_]Value{
.{ .int = 42 },
.{ .float = 3.14 },
.{ .string = "hello" },
.{ .boolean = true },
.null_val,
};
for (values) |v| {
const stdout = std.io.getStdOut().writer();
try v.format(stdout);
try stdout.writeByte('\n');
}
// 访问错误字段会panic(Debug模式)
// const n = values[0].float; // panic! 是.int不是.float
}
switch是Zig中最强大的控制流——它能穷举枚举、解构联合体、匹配范围:
// switch解构标签联合体
fn describe(v: Value) []const u8 {
return switch (v) {
.int => |n| if (n > 0) "positive int" else "non-positive int",
.float => "float",
.string => |s| if (s.len > 10) "long string" else "short string",
.boolean => "boolean",
.null_val => "null",
};
}
// switch + 指针修改
fn increment(v: *Value) void {
switch (v.*) {
.int => |*n| n.* += 1,
.float => |*f| f.* += 1.0,
else => {},
}
}
// switch必须是穷举的!
// 如果Value有5个变体,你必须处理全部5个
// 可以用 else => {} 兜底
当与C互操作时,枚举值可能不完整——使用非穷举枚举:
// 非穷举枚举:允许未知值
const ElfSectionType = enum(u32) {
null = 0,
progbits = 1,
symtab = 2,
strtab = 3,
rela = 4,
// _ 占位符捕获所有未列出的值
_,
pub fn name(self: ElfSectionType) []const u8 {
return switch (self) {
.null => "NULL",
.progbits => "PROGBITS",
.symtab => "SYMTAB",
.strtab => "STRTAB",
.rela => "RELA",
_ => "UNKNOWN", // 未知值
};
}
};
// 从任意整数安全创建
const unknown: ElfSectionType = @enumFromInt(99);
std.debug.print("{}\n", .{unknown.name()}); // "UNKNOWN"
const State = enum {
idle,
connecting,
connected,
closing,
};
const Event = union(enum) {
connect,
data: []const u8,
disconnect,
timeout,
};
fn transition(current: State, event: Event) State {
return switch (current) {
.idle => switch (event) {
.connect => .connecting,
else => .idle,
},
.connecting => switch (event) {
.data => .connected,
.timeout => .idle,
.disconnect => .idle,
.connect => .connecting,
},
.connected => switch (event) {
.disconnect => .closing,
.data => .connected, // 继续接收数据
.timeout => .connected,
.connect => .connected,
},
.closing => .idle,
};
}
shouldLog(level, config)