Zig Cheat Sheet
Core Zig syntax covering variables, error unions, control flow, structs, and compile-time features for systems programming.
Basics
Variables and formatted printing.
const std = @import("std");pub fn main() void { std.debug.print("Hello, {s}!\n", .{"World"}); const x: i32 = 42; // const = immutable var y: i32 = 10; // var = mutable y += 1; std.debug.print("x={d}, y={d}\n", .{ x, y });}
Error Handling
Error unions, catch, and try.
const std = @import("std");const MyError = error{ NotFound, OutOfRange };fn getItem(index: usize) MyError!i32 { if (index > 10) return MyError.OutOfRange; return 42;}pub fn main() void { const value = getItem(3) catch |err| { std.debug.print("error: {}\n", .{err}); return; }; std.debug.print("value: {d}\n", .{value}); // try propagates the error to the caller: // const v = try getItem(3);}
Control Flow
Branching, looping, and scope-exit cleanup.
- if (cond) { } else { }- Standard conditional expression/statement
- while (cond) { }- Loop while a condition holds
- for (items) |item| { }- Iterate over a slice or array
- switch (x) { 1 => ..., else => ... }- Pattern-based branching
- defer cleanup();- Runs cleanup when the current scope exits
- orelse- Provides a default when unwrapping an optional (?T)
Structs & Types
Custom types and Zig-specific type constructs.
- const Point = struct { x: f32, y: f32 };- Defines a struct type
- ?T- Optional type, either a T value or null
- !T- Error union, either an error or a T value
- []const u8- String slice (byte slice), Zig's idiomatic string type
- comptime- Marks a value or code evaluated at compile time
- std.ArrayList(T)- Growable dynamic array from the standard library
Allocators & Memory
Explicit memory management with the allocator interface.
const std = @import("std");pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); const buf = try allocator.alloc(u8, 100); defer allocator.free(buf); var list = std.ArrayList(u8).init(allocator); defer list.deinit(); try list.append('z');}
Comptime & Generics
Compile-time execution powers generic functions and types.
fn Stack(comptime T: type) type { return struct { items: []T, len: usize = 0, fn top(self: @This()) T { return self.items[self.len - 1]; } };}fn max(comptime T: type, a: T, b: T) T { return if (a > b) a else b;}const IntStack = Stack(i32);
Optionals & Null
Nullable values expressed with the ? type prefix.
var maybe: ?i32 = null;maybe = 42;// unwrap with orelse defaultconst value = maybe orelse 0;// capture in ifif (maybe) |v| { std.debug.print("got {}\n", .{v});}// optional pointer, no separate null pointer typevar ptr: ?*i32 = null;
Built-in Testing
Write tests inline and run them with zig test.
const std = @import("std");const expect = std.testing.expect;fn add(a: i32, b: i32) i32 { return a + b;}test "add two numbers" { try expect(add(2, 3) == 5); try std.testing.expectEqual(@as(i32, 0), add(-1, 1));}// run: zig test file.zig
Builtin Functions
Compiler builtins prefixed with @ used across Zig code.
- @import("std")- pull in a module or source file at comptime
- @as(T, x)- explicit type coercion of x to T
- @intCast / @floatCast- narrowing numeric conversions
- @sizeOf(T) / @alignOf(T)- size and alignment in bytes
- @This()- reference to the innermost enclosing struct type
- @TypeOf(x)- the type of an expression at comptime
- @field(obj, "name")- access a struct field by comptime string
- @errorName(e)- string name of an error value
Use defer right after acquiring a resource (allocation, file open) so cleanup code lives next to the acquisition — it always runs, even on early returns or errors.