Ziglings 笔记 40: 只读指针 (*const)

我只看看,不进去

在 Ziglings 的第 40 个练习中,我们遇到了指针与 const 的纠葛。 在 C 语言中,const int *int * const 经常把初学者绕晕。Zig 的语法则更加直观。

挑战:类型不匹配

代码试图定义一个指针 b 指向变量 a。 虽然如果 avar,普通的 *u8 指针是合法的;但这个练习的核心在于理解:如果数据是常量的,或者我们希望它是只读的,指针类型必须做出改变。

Zig 编译器非常严格:你不能创建一个“可变指针”去指向一个“常量数据”。

解决方案

为了最安全地引用数据(或者如果 aconst),我们需要将指针类型声明为 *const u8

const std = @import("std");

pub fn main() void {
    // 原始数据可以是 var (可变) 或 const (不可变)
    var a: u8 = 12;

    // 修复点:显式声明为 *const u8
    // 含义:b 是一个指针,它指向的内容是不可修改的 (const u8)
    // 即使 a 本身是 var,b 也只能“读”不能“写”。
    const b: *const u8 = &a; 

    // b.* = 20; // 如果尝试这行代码,编译器会报错,因为 b 认为是只读的。
    
    std.debug.print("a: {}, b: {}\n", .{ a, b.* });
}

核心知识点总结

1. 指针类型解剖

  • *u8: 读写指针。只能指向 var 变量。
  • *const u8: 只读指针。可以指向 const 变量,也可以指向 var 变量(降级权限)。

2. 权限流向

Zig 允许你放弃写入权限,但不允许你凭空捏造写入权限。

  • var -> *const T (安全:我承诺不改)
  • const -> *T (危险:我试图修改常量)

3. API 设计

在设计函数参数时,这非常有用。 如果你的函数只是读取数据,参数应该写成 input: *const u8。这样调用者既可以传常量指针,也可以传变量指针,而且调用者知道:“放心,这个函数不会修改我的数据”。


后续预告:我们已经学会了指向单个变量的指针。但在 C 语言中,指针和数组是不分家的。在 Zig 中,我们有更好的工具——多项指针 (Many-item Pointers) 和切片。下一篇将是一个挑战!