Zig — Comptime, Allocator, Và Systems Programmer Cần Biết
Zig là ngôn ngữ systems mới nổi với comptime, explicit allocator, không hidden control flow. So sánh với C, Rust và use case thực tế.
Trong thế giới systems programming, C thống trị suốt 50 năm. Rust đến và giải quyết memory safety nhưng kèm learning curve dốc. Zig chọn một con đường khác: giữ sự đơn giản của C, thêm safety checks, và đặc biệt là comptime — meta-programming không cần macro hay code generator.
Zig Là Gì?#
Zig là ngôn ngữ systems programming, tương tự C nhưng hiện đại hơn. Không GC, không runtime, không hidden control flow. Một binary duy nhất (zig) tích hợp sẵn compiler, build system, cross-compiler, và C/C++ compiler.
Những dự án dùng Zig sản xuất:
- Bun — JavaScript runtime, dùng Zig cho FFI, SQLite bindings, và hot path
- TigerBeetle — Financial transaction database, xử lý hàng tỷ giao dịch
- Ghostty — Terminal emulator mới, dùng Zig cho performance
- NullClaw — AI assistant infrastructure, binary 678KB, RAM ~1MB
Comptime — Sát Thủ Của Zig#
comptime là tính năng quan trọng nhất của Zig. Nó cho phép chạy Zig code tại compile time, và kết quả có thể dùng làm type, constant, hoặc code:
fn max(comptime T: type, a: T, b: T) T {
if (a > b) return a else return b
}
// Dùng với nhiều kiểu khác nhau
const x = max(i32, 10, 20); // i32
const y = max(f64, 3.14, 2.71); // f64
// Compiler tự động sinh ra hai hàm riêng biệtzigKhông giống C macro (xử lý text, dễ lỗi) hay Rust proc macro (ngôn ngữ riêng, compile step riêng) — comptime dùng cùng một ngôn ngữ Zig, cùng type system, cùng error messages.
// Kiểm tra điều kiện tại compile time
fn mustBePositive(x: i32) i32 {
comptime {
if (x <= 0) @compileError("x must be positive!");
}
return x;
}
// Sinh type từ dữ liệu
fn Vector(comptime dim: u32) type {
return struct {
data: [dim]f64,
fn length(self: @This()) f64 {
var sum: f64 = 0;
for (self.data) |v| sum += v * v;
return @sqrt(sum);
}
};
}
const Vec3 = Vector(3); // Type được sinh tại comptimezigAllocator — Memory Management Minh Bạch#
Zig không có GC, không RAII, không borrow checker. Thay vào đó: mọi function dùng memory đều nhận allocator làm tham số.
fn readFile(allocator: std.mem.Allocator, path: []const u8) ![]u8 {
const file = try std.fs.cwd().openFile(path, .{});
defer file.close();
const content = try file.readToEndAlloc(allocator, 1_000_000);
return content;
// Caller chịu trách nhiệm free
}zigCác allocator có sẵn:
| Allocator | Mục đích |
|---|---|
GeneralPurposeAllocator | Debug (phát hiện leak/double-free) |
page_allocator | OS page (gọi mmap trực tiếp) |
ArenaAllocator | Free tất cả cùng lúc |
FixedBufferAllocator | Pre-allocated buffer |
StackAllocator | LIFO allocation |
Arena Pattern (Quan Trọng Nhất)#
Arena là pattern phổ biến trong Zig — allocate nhiều lần, free một lần:
fn handleRequest() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit(); // Dọn tất cả khi thoát
const alloc = arena.allocator();
const name = try alloc.dupe(u8, "Alice");
const data = try alloc.alloc(u8, 1024);
// Không cần free từng cái — arena.deinit() dọn hết
}zigBun dùng arena này cho mỗi HTTP request. TigerBeetle dùng cho mỗi transaction. Kết quả: gần như zero malloc/free overhead.
So Sánh Với C#
| Tính năng | C | Zig |
|---|---|---|
| Memory | malloc/free | Allocator interface |
| Safety | Không | Runtime checks (debug), bounds check |
| Generic | Macro (#define) | comptime (type-safe) |
| Build | Make/CMake | build.zig (tích hợp) |
| Cross-compile | Toolchain riêng | zig cc (built-in) |
| Slice | Pointer + size thủ công | []u8 (built-in, bounds-checked) |
| Defer | Không | defer / errdefer |
| Error handling | errno | Error union (! type) |
| Optionals | NULL pointer | ?T (optional type) |
So Sánh Với Rust#
| Tính năng | Rust | Zig |
|---|---|---|
| Safety model | Compile-time borrow check | Runtime checks (debug, tắt ở release) |
| Learning curve | Cao (ownership, lifetime) | Thấp (C-like mental model) |
| Metaprogramming | Proc macro (ngôn ngữ riêng) | comptime (cùng ngôn ngữ) |
| Memory | RAII + ownership | Explicit allocator passing |
| Hidden control flow | Drop, deref coercion, implicit move | None by design |
| Compile time | Chậm (monomorphization) | Nhanh |
| C interop | FFI + unsafe | First-class (shared ABI) |
| Binary size | Lớn (monomorph + std) | Nhỏ (chỉ code dùng) |
Code Cụ Thể#
Đọc File#
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const alloc = gpa.allocator();
const args = try std.process.argsAlloc(alloc);
defer std.process.argsFree(alloc, args);
if (args.len < 2) {
try std.io.getStdOut().writeAll("Usage: cat-file <file>\n");
return;
}
const content = try std.fs.cwd().readFileAlloc(alloc, args[1], 10_000_000);
defer alloc.free(content);
try std.io.getStdOut().writeAll(content);
}zigArrayList#
const std = @import("std");
const testing = std.testing;
test "ArrayList basic" {
var list = std.ArrayList(i32).init(testing.allocator);
defer list.deinit();
try list.append(10);
try list.append(20);
try list.append(30);
try testing.expectEqual(10, list.items[0]);
try testing.expectEqual(@as(usize, 3), list.items.len);
}zigZig có testing built-in — không cần thư viện ngoài.
Cross-Compile Với zig cc#
# Build cho macOS, Linux, Windows từ một máy
zig build-exe main.zig -target x86_64-linux
zig build-exe main.zig -target aarch64-linux
zig build-exe main.zig -target x86_64-windows
# Dùng zig cc thay gcc (compile C/C++)
zig cc -o hello hello.c -target aarch64-linuxbashZig bundles LLVM và các target triple — cross-compile không cần cài toolchain riêng.
Khi Nào Dùng Zig?#
Phù hợp:
- Systems programming (OS, driver, embedded)
- Tools và CLI (binary nhỏ, start nhanh)
- Game engine (cần control memory)
- Performance-critical path (cần predictable latency)
- C/C++ project muốn modernization dần dần (Zig import .h trực tiếp)
Không phù hợp (hiện tại):
- Web app (dùng Go, Rust, TypeScript)
- Data science (Python)
- Ecosystem còn nhỏ (ít thư viện)
- Production GUI (chưa có framework ổn định)
Kết Luận#
Zig là ngôn ngữ dành cho người muốn viết systems code mà không muốn học borrow checker của Rust hay vật lộn với macro của C.
Comptime là killer feature: generic type-safe, không cần code generator, chạy ngay trong compiler. Allocator pattern minh bạch: bạn biết ai allocate, ai free, dùng allocator nào. Build system tích hợp: không Make/CMake, cross-compile một lệnh.
Zig 0.16+ đã sẵn sàng cho production. Bun, TigerBeetle, Ghostty, NullClaw đang chạy trên nó hàng ngày.