Ziglings 笔记 54: 多项指针与类型大一统
指针的完全体
在 Ziglings 的第 54 个练习中,我们终于集齐了 Zig 指针家族的最后一块拼图:多项指针 (Many-item Pointer)。
在此之前,我们学过单项指针 *T(只能指一个)和切片 []T(带长度)。但如果你需要像 C 语言那样操作一个“不知道长度的数组指针”怎么办?Zig 提供了 [*]T。
挑战:找回丢失的长度
代码中我们有一个 zen_manyptr,它指向一段字符串内存,但它的类型是 [*]const u8。这意味着编译器只知道它指向哪里,但不知道它有多长。
为了使用 {s} 格式化打印它,我们需要把它转换回切片 []const u8。
解决方案
我们需要手动指定切片的边界:
const std = @import("std");
pub fn main() void {
// 原始数据:指向长为 21 的数组的指针
const zen12: *const [21]u8 = "Memory is a resource.";
// 转换为多项指针:此时长度信息丢失了!
// [*]const u8 就像 C 语言里的 const char*
const zen_manyptr: [*]const u8 = zen12;
// 核心操作:指针 -> 切片
// 因为多项指针不知道长度,我们必须显式通过 [0..N] 告诉编译器截取多少
// 字符串 "Memory is a resource." 的长度正好是 21
const zen12_string: []const u8 = zen_manyptr[0..21];
std.debug.print("{s}\n", .{zen12_string});
}
核心知识点总结
1. [*]T vs []T
这是系统编程中常见的权衡:
- 切片 (
[]T):胖指针。占用 2 个字长(地址 + 长度)。安全,知道边界。 - 多项指针 (
[*]T):瘦指针。占用 1 个字长(地址)。不安全,不知道边界,但与 C 语言兼容性好。
2. 指针速查表 (The Cheatsheet)
练习中的注释总结了 Zig 所有的指针类型,非常值得收藏:
u8: 值。*u8: 单个指针。[*]u8: C 风格指针(多项)。[]u8: 切片(指针 + 长度)。[N]u8: 数组(固定长度的值)。*[N]u8: 指向数组的单指针。
3. 何时使用?
在纯 Zig 代码中,99% 的情况你应该使用切片 ([]T)。
只有在以下情况使用多项指针 [*]T:
- 调用 C 语言接口。
- 实现底层的内存分配器。
- 进行高性能的指针算术运算。
后续预告:指针和数组我们已经学透了。接下来的练习将进入一个新的高阶话题:泛型 (Generics)。Zig 没有 <T> 这样的语法,它是如何在编译期实现泛型的呢?下一篇见分晓。