Ziglings 笔记 41: 指针的双重可变性
指针的“套娃”
在 Ziglings 的第 41 个练习中,我们遇到了指针最烧脑的部分。
在上一节我们区分了 *u8 和 *const u8。这一次,我们要在变量声明的前面再加一层 var 或 const。
这就像是一个逻辑矩阵,我们需要搞清楚到底什么是可变的。
挑战:全能指针
我们需要定义一个指针 p,它必须具备两项能力:
- 换目标:一开始指向
foo,后来改成指向bar。 - 改数据:能够对指向的数字进行
+= 1操作。
解决方案
我们需要组合 var(允许重定向)和 *u8(允许修改数据):
const std = @import("std");
pub fn main() void {
var foo: u8 = 5;
var bar: u8 = 10;
// 核心定义:
// 1. var: 说明 p 这个变量本身是可以修改的(可以存新地址)。
// 2. *u8: 说明 p 指向的数据是可变的(可以修改内存里的值)。
var p: *u8 = undefined;
// 动作 1: 指向 foo 并修改它
p = &foo; // 重定向
p.* += 1; // 修改值 (foo 变成 6)
// 动作 2: 指向 bar 并修改它
p = &bar; // 重定向
p.* += 1; // 修改值 (bar 变成 11)
std.debug.print("foo={}, bar={}\n", .{ foo, bar });
}
核心知识点总结
我们可以把指针看作包含两个层面的对象:
1. 指针本身 (Reference)
const p: 这是一个固定的指针。一旦初始化指向了 A,就不能再指向 B。var p: 这是一个游动的指针。可以随时让它指向别的地方。
2. 指向的内容 (Value)
*const T: 这是一个只读视图。通过这个指针,你不能修改数据。*T: 这是一个读写视图。通过这个指针,你可以修改数据。
四种组合速查
| 定义 | 能改地址吗?(p = &y) | 能改值吗?(p.* += 1) |
|---|---|---|
const p: *const u8 | ❌ No | ❌ No |
const p: *u8 | ❌ No | ✅ Yes |
var p: *const u8 | ✅ Yes | ❌ No |
var p: *u8 | ✅ Yes | ✅ Yes |
本题要求的就是最后一种“双重可变”的情况。
后续预告:指针不仅仅是单数的。如果我想用指针操作数组(比如 C 语言中的 ptr++),在 Zig 中该怎么做?下一篇我们将探讨指针算术与多项指针。