Ziglings 笔记 37: 万物皆可结构体 (Structs)
数据的容器
在 Ziglings 的第 37 个练习中,我们终于遇到了 Struct (结构体)。
在此之前,如果我们想描述一个游戏角色,可能需要定义 role_wiz, gold_wiz, hp_wiz 等一堆散乱的变量。而结构体允许我们将这些相关的数据打包在一起。
挑战:RPG 角色卡
任务是为一个 RPG 角色系统添加生命值(Health)属性:
- 在
Character类型定义中添加health字段。 - 在初始化角色
glorp_the_wise时设置具体的生命值。
解决方案
这是完整的代码实现:
const std = @import("std");
const Role = enum {
wizard,
thief,
bard,
warrior,
};
// 1. 定义结构体
// struct 关键字用于定义一组字段的集合
const Character = struct {
role: Role,
gold: u32,
experience: u32,
health: u8, // 新增:生命值,使用 u8 (0-255) 就够了
};
pub fn main() void {
// 2. 初始化结构体实例
// 注意:Zig 要求必须初始化所有字段(除非字段有默认值)
var glorp_the_wise = Character{
.role = Role.wizard,
.gold = 20,
.experience = 10,
// 关键语法:字段名前面要加点 (.)
.health = 100,
};
glorp_the_wise.gold += 5;
glorp_the_wise.health -= 10;
std.debug.print("Your wizard has {} health and {} gold.\n", .{
glorp_the_wise.health,
glorp_the_wise.gold,
});
}
核心知识点总结
1. 语法解剖
Zig 的结构体初始化语法非常独特:
MyStruct{
.field1 = value1,
.field2 = value2,
}
那个前导点号 (.) 是必须的。它不仅让代码在视觉上更清晰(一眼看出这是字段赋值),而且有助于编译器进行类型推导。
2. 内存布局
虽然这个练习没有涉及,但值得一提的是,Zig 的 struct 默认不保证内存布局顺序(为了优化对齐,编译器可能会重排字段)。如果你需要和 C 语言交互,需要使用 extern struct。
3. 类型安全
结构体让数据传递变得安全。你不能把一个 Character 传给一个需要 Item 的函数,即使它们碰巧有相同的字段。
后续预告:结构体只能存数据吗?在 Zig 中,结构体其实可以像类(Class)一样拥有方法(Methods)。下一篇我们将学习如何把函数放进结构体里。