Ziglings 笔记 43: 结构体指针与自动解引用
告别箭头操作符
在 Ziglings 的第 43 个练习中,我们开始将指针用于更复杂的场景:结构体引用。
如果你写过 C++,你一定很熟悉 . 和 -> 的区别:对象用点,指针用箭头。初学者经常搞混。
Zig 在这里做了一个非常棒的设计决定:统统用点 (.)。
挑战:寻找导师
我们需要完善一个 RPG 角色系统。
- 角色可以有导师(Mentor),这通过一个指向另一个
Character的指针来实现。 - 我们需要编写一个函数
printCharacter,它接收角色的指针而不是副本。
解决方案
这是修复后的 main 函数:
const std = @import("std");
// ... 结构体定义省略 ...
pub fn main() void {
// 导师:Mighty Krodor
// 注意:这里没有初始化 .health,因为它有默认值 100
var mighty_krodor = Character{
.class = Class.wizard,
.gold = 10000,
.experience = 2340,
};
// 学徒:Glorp
var glorp = Character{
.class = Class.wizard,
.gold = 10,
.experience = 20,
// 关键点:取地址 (&)
// 我们把 Krodor 的地址赋给了 mentor 字段,建立了链接
.mentor = &mighty_krodor,
};
// 修复点:传递引用
// printCharacter 期望的是 *Character (指针),所以我们要传 &glorp
printCharacter(&glorp);
}
核心知识点总结
1. 自动解引用 (Auto-dereference)
在 printCharacter 函数中,参数 c 是一个指针 *Character。
但在访问字段时,我们直接写 c.gold。
Zig 编译器非常聪明,它看到 c 是指针而 gold 是字段,就会自动帮我们解引用。这意味着在 Zig 中,你永远不需要写 c->gold。
2. 结构体的默认值
const Character = struct {
// ...
health: u8 = 100,
};
这个功能极大地简化了初始化代码。对于那些不常变动的配置项,设置默认值是最佳实践。
3. 枚举的简写
在 switch (c.class) 中,我们使用了 .wizard 而不是 Class.wizard。
只要上下文类型明确,Zig 允许我们要么省略枚举类型名,直接用点号加成员名。这让代码读起来更像一种领域特定语言 (DSL)。
后续预告:我们一直在用指针。但 C 语言老手可能会问:Zig 有没有更安全的“引用”?下一篇,我们将进入 Quiz 5,在进入 Optionals 章节前做最后一次复习。