Quick Reference
Zig Quick Reference
Common Patterns
Memory Management
// Allocator setup (in main)
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit(); // Catches leaks
const allocator = gpa.allocator();
// Allocation
const buffer = try allocator.alloc(u8, size);
defer allocator.free(buffer);
// Array vs Slice
var array: [100]u8 = undefined; // Stack, fixed size
const slice = try allocator.alloc(u8, 100); // Heap, dynamic
Error Handling
// Propagate errors up
const result = try mightFail();
// Handle specific error
const result = mightFail() catch |err| {
std.debug.print("Error: {}\n", .{err});
return err;
};
// Provide default
const result = mightFail() catch default_value;
// Conditional
if (mightFail()) |value| {
// Success path
} else |err| {
// Error path
}
Struct Patterns
const Thing = struct {
data: []u8,
allocator: std.mem.Allocator,
// Constructor
fn init(allocator: std.mem.Allocator, size: usize) !Thing {
return Thing{
.data = try allocator.alloc(u8, size),
.allocator = allocator,
};
}
// Destructor
fn deinit(self: *Thing) void {
self.allocator.free(self.data);
}
// Const method
fn get(self: *const Thing, index: usize) u8 {
return self.data[index];
}
// Mutable method
fn set(self: *Thing, index: usize, value: u8) void {
self.data[index] = value;
}
};
// Usage
var thing = try Thing.init(allocator, 100);
defer thing.deinit();
ArrayList (Zig 0.15.2)
// Initialize
var list: std.ArrayList(u8) = .{};
defer list.deinit(allocator);
// Common operations
try list.append(allocator, item);
try list.appendSlice(allocator, slice);
const last = list.pop();
const item = list.items[i];
// Access
list.items // The slice
list.items.len // Length
list.capacity // Allocated capacity
Slices
const str = "hello world";
str[0] // First char
str[1..] // From index 1 to end
str[0..5] // First 5 chars (exclusive end)
str[str.len-1] // Last char
// Iterate
for (str) |c| {
// Each character
}
for (str, 0..) |c, i| {
// Character and index
}
For Loops
// Range
for (0..10) |i| { ... }
// Slice
for (slice) |item| { ... }
// With index
for (slice, 0..) |item, i| { ... }
// Multiple at once
for (slice1, slice2) |a, b| { ... }
// Basic
std.debug.print("{}\n", .{value});
// Specific format
{d} // Decimal
{x} // Hex lowercase
{X} // Hex UPPERCASE
{b} // Binary
{s} // String
{c} // Character
{e} // Scientific notation
// With formatting
{x:0>2} // Hex, zero-padded to 2 chars
{d:4} // Decimal, width 4
{s:<10} // String, left-aligned in 10 chars
Common Builtins
@min(a, b) // Minimum
@max(a, b) // Maximum
@intCast(value) // Convert integer types
@as(Type, value) // Type coercion
@sizeOf(Type) // Size of type
@TypeOf(value) // Get type
@memset(slice, value) // Fill memory
@memcpy(dest, src) // Copy memory
Type Conversions
// Explicit casts (required!)
const a: u8 = 255;
const b: u16 = @as(u16, a); // Widen
const c: usize = @intCast(some_int); // Convert
// String to number
const num = try std.fmt.parseInt(i32, "123", 10);
// Number to string
var buf: [100]u8 = undefined;
const str = try std.fmt.bufPrint(&buf, "{d}", .{value});
File I/O (Zig 0.15.2)
// Read entire file
const file = try std.fs.cwd().openFile("path.txt", .{});
defer file.close();
const contents = try file.readToEndAlloc(allocator, max_size);
defer allocator.free(contents);
// Write file
const file = try std.fs.cwd().createFile("path.txt", .{});
defer file.close();
try file.writeAll("content");
// Buffered I/O
var buffer: [4096]u8 = undefined;
var writer = file.writer(&buffer);
try writer.print("Value: {}\n", .{42});
try writer.flush();
Zig 0.15.2 API Changes
stdout/stderr
// Old:
const stdout = std.io.getStdOut().writer();
// New:
var buffer: [4096]u8 = undefined;
var stdout_writer = std.fs.File.stdout().writer(&buffer);
const stdout = &stdout_writer.interface;
ArrayList
// Old:
var list = std.ArrayList(u8).init(allocator);
// New:
var list: std.ArrayList(u8) = .{};
defer list.deinit(allocator); // Pass allocator!
Compression
// Old:
const zlib = std.compress.zlib;
// New:
const flate = std.compress.flate;
var decomp = flate.Decompress.init(&reader, .zlib, &buffer);
Sleep
// Old:
std.time.sleep(ns);
// New:
std.Thread.sleep(ns);
Common Gotchas
1. Unused Variables
const x = 5; // Error if never used
// Fix:
_ = x; // Explicitly discard
2. Mutable vs Const
const x = 5;
x = 10; // Error!
var y = 5;
y = 10; // OK
3. String Literals are const
var str = "hello"; // Type: *const [5:0]u8
str[0] = 'H'; // Error: const
// Need mutable:
var buf = [_]u8{'h', 'e', 'l', 'l', 'o'};
buf[0] = 'H'; // OK
4. Integer Types Don’t Auto-Convert
const a: u8 = 5;
const b: u16 = a; // Error!
const b: u16 = @intCast(a); // OK
5. Undefined Behavior is a Compile Error
var index: usize = 100;
var arr = [_]u8{1, 2, 3};
const x = arr[index]; // Runtime panic in debug, UB in release
// Zig catches at compile time when possible
const x = arr[100]; // Compile error!
Testing
test "basic test" {
const result = add(2, 3);
try std.testing.expectEqual(@as(i32, 5), result);
}
// Run tests:
// zig test file.zig
Build System
// build.zig
pub fn build(b: *std.Build) void {
const exe = b.addExecutable(.{
.name = "myapp",
.root_source_file = b.path("src/main.zig"),
.target = b.standardTargetOptions(.{}),
.optimize = b.standardOptimizeOption(.{}),
});
b.installArtifact(exe);
}
# Commands
zig build # Build
zig build run # Build and run
zig build test # Run tests
zig build --help # See options
Useful Links
Philosophy Reminders
- No hidden control flow
- No hidden allocations
- No preprocessor, no macros
- If it compiles, it’s well-defined
- Explicit is better than implicit