解答10: 構造体と列挙型の完全理解
概要
この解答では、Zigの複合型である構造体、列挙型、共用体について学びます。
Part 1: 構造体
const std = @import("std");
const Point = struct {
x: f32,
y: f32,
pub fn init(x: f32, y: f32) Point {
return .{ .x = x, .y = y };
}
pub fn distance(self: Point, other: Point) f32 {
const dx = self.x - other.x;
const dy = self.y - other.y;
return @sqrt(dx * dx + dy * dy);
}
pub fn translate(self: *Point, dx: f32, dy: f32) void {
self.x += dx;
self.y += dy;
}
};
const Config = struct {
timeout_ms: u32 = 5000,
max_retries: u8 = 3,
verbose: bool = false,
};
Part 2: 列挙型
const std = @import("std");
const Direction = enum {
north,
south,
east,
west,
pub fn opposite(self: Direction) Direction {
return switch (self) {
.north => .south,
.south => .north,
.east => .west,
.west => .east,
};
}
};
const HttpStatus = enum(u16) {
ok = 200,
created = 201,
bad_request = 400,
not_found = 404,
pub fn isSuccess(self: HttpStatus) bool {
return @intFromEnum(self) >= 200 and @intFromEnum(self) < 300;
}
};
Part 3: 共用体
const std = @import("std");
const Value = union(enum) {
int: i64,
float: f64,
string: []const u8,
boolean: bool,
null_val,
pub fn isNumeric(self: Value) bool {
return switch (self) {
.int, .float => true,
else => false,
};
}
};
Part 4: メモリレイアウト
const std = @import("std");
const Normal = struct {
a: u8, // + padding
b: u32,
c: u8, // + padding
};
const Packed = packed struct {
a: u8,
b: u32,
c: u8,
};
pub fn layoutDemo() void {
std.debug.print("Normal size: {}, Packed size: {}\n", .{
@sizeOf(Normal),
@sizeOf(Packed),
});
}
ポイント解説
| 特性 | struct | enum | union |
|---|---|---|---|
| データ格納 | 全フィールド同時 | 単一の値 | いずれか一つ |
| 用途 | データのグループ化 | 状態の列挙 | バリアント型 |
よくある間違い
// 誤り: 変更メソッドでコピーを受け取る
pub fn increment(self: Counter) void {
self.value += 1; // コピーを変更
}
// 正しい: ポインタで受け取る
pub fn increment(self: *Counter) void {
self.value += 1;
}
自己確認チェックリスト
- [ ] selfとself: *の使い分けを理解しているか
- [ ] タグ付き共用体の用途を説明できるか
- [ ] struct, packed struct, extern structの違いを把握しているか