Ziglings 笔记 49: 阶段性测验 6 - 双向奔赴的大象
进击的大象
这是 Ziglings 的第六次阶段性测验(Quiz 6)。我们再次拿起了大象链表的例子,但这次升级了!
在此之前,我们的大象只能手拉手排成一行单向行走。如果走到最后一只大象,我们就回不去了。为了解决这个问题,我们需要引入“象鼻”的概念,让大象也能牵住前面伙伴的尾巴。
在计算机科学中,这就是从 单向链表 进化为 双向链表 的过程。
挑战:实现回溯
我们需要在 Elephant 结构体中实现关于 trunk (象鼻) 的方法,使得程序能够:
- 正向遍历:A -> B -> C
- 反向遍历:C -> B -> A
解决方案
这是补充完整的代码逻辑:
const std = @import("std");
const Elephant = struct {
letter: u8,
tail: ?*Elephant = null, // 指向下一只 (Next)
trunk: ?*Elephant = null, // 指向上一只 (Prev)
visited: bool = false,
// Tail 方法 (Next)
pub fn getTail(self: *Elephant) *Elephant {
return self.tail.?;
}
pub fn hasTail(self: *Elephant) bool {
return (self.tail != null);
}
// Trunk 方法 (Prev) - 我们的任务是实现这部分
// 逻辑与 Tail 完全对称
pub fn getTrunk(self: *Elephant) *Elephant {
return self.trunk.?; // 同样使用 .? 快速解包
}
pub fn hasTrunk(self: *Elephant) bool {
return (self.trunk != null);
}
// ... 其他打印方法 ...
};
pub fn main() void {
var elephantA = Elephant{ .letter = 'A' };
var elephantB = Elephant{ .letter = 'B' };
var elephantC = Elephant{ .letter = 'C' };
// 链接 Tails (正向)
elephantA.tail = &elephantB;
elephantB.tail = &elephantC;
// 链接 Trunks (反向)
// 注意:A 没有 trunk (null),C 没有 tail (null)
elephantB.trunk = &elephantA;
elephantC.trunk = &elephantB;
visitElephants(&elephantA);
}
fn visitElephants(first_elephant: *Elephant) void {
var e = first_elephant;
// 1. 顺藤摸瓜 (Follow Tails)
while (true) {
e.print(); // A -> B -> C
if (e.hasTail()) {
e = e.getTail();
} else {
break; // 停在 C
}
}
// 2. 倒打一耙 (Follow Trunks)
while (true) {
e.print(); // C -> B -> A
if (e.hasTrunk()) {
e = e.getTrunk();
} else {
break; // 停在 A
}
}
}
核心知识点回顾
1. 双向链表 (Doubly Linked List)
通过同时维护 next (tail) 和 prev (trunk) 指针,我们在内存中构建了一个可以自由前后移动的数据结构。这在实现诸如浏览器的“前进/后退”功能或文本编辑器的“撤销/重做”栈时非常有用。
2. 结构体方法的封装
我们在 main 函数和 visitElephants 函数中,完全不需要知道 trunk 是 ?*Elephant 类型。我们只调用了 hasTrunk() 和 getTrunk()。这种封装让业务逻辑代码非常干净,也更安全。
3. 可选类型的边界控制
?*Elephant 类型强制我们处理 null。在链表中,null 天然充当了哨兵(Sentinel)的角色,告诉我们“到头了”。结合 hasTrunk() 的检查,我们编写出了不会越界崩溃的健壮代码。
后续预告:顺利通过 Quiz 6!我们已经把基本类型玩得很溜了。接下来的练习可能会带我们去探索一些更抽象的概念,比如“什么都没有”到底有几种写法?下一篇我们聊聊 void, undefined 和空结构体。