Ziglings 笔记 42: 引用传递 (Pass by Reference)
拿到了修改权限
在 Ziglings 的第 42 个练习中,我们终于打破了“函数参数不可变”的限制。 在此之前,如果我们想让一个函数改变某个变量的值,我们束手无策,因为 Zig 的函数参数默认是常量。
现在,通过指针,我们学会了引用传递。
挑战:把一切变成 5
我们需要编写一个 makeFive 函数。
- 它接收一个指向
u8的指针。 - 它需要把这个指针指向的内存里的值修改为 5。
- 我们需要用它来修改一个普通变量和一个数组中的特定元素。
解决方案
这是实现代码:
const std = @import("std");
pub fn main() void {
var num: u8 = 1;
var more_nums = [_]u8{ 1, 1, 1, 1 };
// 1. 传递普通变量的地址
// &num 的类型是 *u8
makeFive(&num);
std.debug.print("num: {}, ", .{num});
// 2. 传递数组元素的地址
// &more_nums[2] 的类型也是 *u8
// 这展示了数组元素本质上就是内存中的普通变量
makeFive(&more_nums[2]);
std.debug.print("more_nums: ", .{});
for (more_nums) |n| {
std.debug.print("{} ", .{n});
}
std.debug.print("\n", .{});
}
// 函数签名:接收 *u8 (可变指针)
fn makeFive(x: *u8) void {
// 核心操作:解引用并赋值
// x 是地址,x.* 是地址里的值
x.* = 5;
}
核心知识点总结
1. 什么时候用指针?
口诀很简单:
- 如果你只想读取数据:直接传值(
u8)或者传常量指针(*const u8,用于大数据结构)。 - 如果你想修改数据:必须传可变指针(
*u8)。
2. 解引用赋值
在 C 语言中,我们写 *x = 5。
在 Zig 中,我们写 x.* = 5。
这种后缀语法 .* 提醒我们:我们正在操作的是指针指向的对象,而不是指针本身。
3. 数组即内存
这个练习生动地演示了数组仅仅是一排紧挨着的变量。我们可以获取其中任何一个格子的地址,并把它当作一个独立的指针传给函数。这就是系统编程底层的魅力。
后续预告:我们已经习惯了指向单个元素的指针。但是,如果我们要处理一串数据(比如 C 语言中的字符串或缓冲区),单个指针还够用吗?下一篇我们将探讨 Zig 的多项指针 (Many-item Pointers)。