Zig

2025-03-311 出链3 引用

保持高级语言表达能力的同时,把数据如何表示、代码何时生成、运行时发生什么尽可能交还给程序员

维度 Zig 的选择
数据如何存在 显式布局与表示
代码如何复用 comptime 生成和特化
运行时如何变化 显式函数指针、tagged union、vtable
资源如何管理 显式 allocator 与生命周期
错误如何传播 显式 error union
成本在哪里发生 尽可能可从源码判断
  1. 简单(代码所见即所得):调试代码,而不是调试编程语言知识(比如Rust的所有权借用、Go的GC/调度器/接口动态分派)
  • 无隐藏控制流(手动管理内存+defer/errdefer释放资源;!T 错误路径显式化、?T空值显式化...),没有隐藏运行时
  • 无隐藏内存分配(内存分配是显式的,如果一个函数内部需要分配堆内存,需要接收一个allocator的参数)
  • 无预处理器、宏
  1. 基于编译时代码执行、惰性求值的元编程:
  • 编译期执行函数
  • 把类型当作值一样操作(无运行时开销,类型内省)
  • Comptime 会以目标平台的类型、布局与运算规则为基础,在编译期完成求值
  1. 以统一工具链渐进改造 C/C++ 工程:
  • zig build 提供统一构建与跨平台编译能力
  • 与现有 C/C++ 项目的无缝衔接(zig替代c编译链、c使用zig模块)

comptime 编译期运算

Zig 把类型抽象、代码生成大量放在编译期,比如泛型,反射...

  1. anytype 类型,用于函数参数推导,调用时确定具体类型,然后编译对应实现
  2. comptime + type
    • comptime 可以修饰函数调用、代码块、表达式,表示这些指令需要在编译期执行;可以修饰参数,表示这个值必须在编译期已知
    • 类型T也是某种值,其类型是type:参数comptime T: type接收一个类型

应用:数据处理过程中,如果只依赖编译期已知的信息的计算,可以提前在编译期完成。

运行时动态性

  1. union(enum) + switch,可以看作显式的、封闭世界的动态分派
zig
const Writer = union(enum) {
    file: *FileWriter,
    socket: *SocketWriter,
    memory: *MemoryWriter,
 
    pub fn write(self: Writer, data: []const u8) !usize {
        return switch (self) {
            .file => |w| w.write(data),
            .socket => |w| w.write(data),
            .memory => |w| w.write(data),
        };
    }
};
  1. 函数指针
zig
const Callback = struct {
    context: *anyopaque,
    callFn: *const fn (*anyopaque, []const u8) void,
 
    pub fn call(self: Callback, data: []const u8) void {
        self.callFn(self.context, data);
    }
};
  1. 定义 vtable
zig
const Writer = struct {
    ptr: *anyopaque,
    vtable: *const VTable,
 
    const VTable = struct {
        write: *const fn (*anyopaque, []const u8) anyerror!usize,
        flush: *const fn (*anyopaque) anyerror!void,
    };
 
    pub fn write(self: Writer, data: []const u8) !usize {
        return self.vtable.write(self.ptr, data);
    }
 
    pub fn flush(self: Writer) !void {
        return self.vtable.flush(self.ptr);
    }
};

NOTE: comptime 可以帮助构造运行时动态机制,比如将某个具体类型转换成符合vtable的类型(类似Go的interface)

错误处理

rust的错误处理目标一致:错误是类型系统的一部分,不可被静默忽略;

但有区别:

E!T内建于编译器,错误E只能是error set错误集合:

  • 穷举:switch穷举所有错误
  • 传播:try向上传播给调用方
  • 组合:错误集可通过||合并或由编译器自动推断,组合轻松
  • 信息:错误仅是名字(整数),无法携带丰富信息,需额外方式传递
  • 恢复:就地降级(catch |_| default_value

dot syntax

. 经常表示让编译器从上下文推断左边缺失的类型/对象

  1. 第一类是 contextual shorthand:类型你已经知道了,我就不再写。
  2. 第二类是 postfix operator / member syntax
  • Anonymous Struct Literals: .{}
  • Anonymous Tuples and Arrays
  • Enum Literal Inference: .variant
  • Pointer Dereferencing: .*

struct

Zig 的 struct 不只是 data layout 它同时也是一个namespace

links

  1. https://mitchellh.com/zig
  2. https://matklad.github.io/2025/08/09/zigs-lovely-syntax.html

评论