blog.dopana

Back

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ệt
zig

Khô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.

Allocator — 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
}
zig

Các allocator có sẵn:

AllocatorMục đích
GeneralPurposeAllocatorDebug (phát hiện leak/double-free)
page_allocatorOS page (gọi mmap trực tiếp)
ArenaAllocatorFree tất cả cùng lúc
FixedBufferAllocatorPre-allocated buffer
StackAllocatorLIFO 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
}
zig

Bun 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ăngCZig
Memorymalloc/freeAllocator interface
SafetyKhôngRuntime checks (debug), bounds check
GenericMacro (#define)comptime (type-safe)
BuildMake/CMakebuild.zig (tích hợp)
Cross-compileToolchain riêngzig cc (built-in)
SlicePointer + size thủ công[]u8 (built-in, bounds-checked)
DeferKhôngdefer / errdefer
Error handlingerrnoError union (! type)
OptionalsNULL pointer?T (optional type)

So Sánh Với Rust#

Tính năngRustZig
Safety modelCompile-time borrow checkRuntime checks (debug, tắt ở release)
Learning curveCao (ownership, lifetime)Thấp (C-like mental model)
MetaprogrammingProc macro (ngôn ngữ riêng)comptime (cùng ngôn ngữ)
MemoryRAII + ownershipExplicit allocator passing
Hidden control flowDrop, deref coercion, implicit moveNone by design
Compile timeChậm (monomorphization)Nhanh
C interopFFI + unsafeFirst-class (shared ABI)
Binary sizeLớn (monomorph + std)Nhỏ (chỉ code dùng)

Code Cụ Thể#

Đọc File#

ArrayList#

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);
}
zig

Zig 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-linux
bash

Zig 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.

Tài liệu tham khảo#