B.1 Basic Program
const std = @import("std");
pub fn main() void {
std.debug.print("Hello, Zig!\n", .{});
}main is where the program starts. std is the standard library. std.debug.print prints formatted text.
B.2 Build and Run
zig run main.zigCompile and run one file.
zig build-exe main.zigCompile one file into an executable.
zig test main.zigRun tests in one file.
zig buildRun the project build script.
B.3 Constants and Variables
const x = 10;
var y = 20;Use const when the value does not change. Use var when the value changes.
var count: i32 = 0;
count += 1;You can write the type explicitly after :.
B.4 Common Types
const a: i32 = -10;
const b: u32 = 10;
const c: f64 = 3.14;
const ok: bool = true;
const ch: u8 = 'A';Common integer types:
| Type | Meaning |
|---|---|
i8, i16, i32, i64 | Signed integers |
u8, u16, u32, u64 | Unsigned integers |
usize | Size/index type |
isize | Signed pointer-sized integer |
B.5 Arrays and Slices
const nums = [_]i32{ 1, 2, 3 };This is a fixed array.
const first = nums[0];Indexing starts at 0.
const part = nums[0..2];This creates a slice containing items at indexes 0 and 1.
Array type:
[3]i32Slice type:
[]const i32B.6 Strings
const name = "Zig";A string literal is a slice of bytes.
const text: []const u8 = "hello";Zig strings are usually UTF-8 bytes. Zig does not hide text encoding from you.
B.7 If
if (x > 0) {
std.debug.print("positive\n", .{});
} else {
std.debug.print("not positive\n", .{});
}if can also produce a value:
const sign = if (x >= 0) 1 else -1;B.8 Switch
const result = switch (value) {
0 => "zero",
1 => "one",
else => "many",
};switch must handle all possible cases, or it must include else.
B.9 While Loop
var i: usize = 0;
while (i < 5) : (i += 1) {
std.debug.print("{}\n", .{i});
}The expression after : runs after each loop iteration.
B.10 For Loop
const nums = [_]i32{ 10, 20, 30 };
for (nums) |n| {
std.debug.print("{}\n", .{n});
}With index:
for (nums, 0..) |n, i| {
std.debug.print("{}: {}\n", .{ i, n });
}B.11 Functions
fn add(a: i32, b: i32) i32 {
return a + b;
}Call it:
const x = add(2, 3);A function that returns nothing uses void:
fn sayHello() void {
std.debug.print("hello\n", .{});
}B.12 Errors
const MyError = error{
NotFound,
InvalidInput,
};A function that can fail:
fn load() MyError!void {
return MyError.NotFound;
}Use try to propagate the error:
try load();Use catch to handle it:
load() catch |err| {
std.debug.print("error: {}\n", .{err});
};B.13 Optionals
var maybe_number: ?i32 = null;An optional value is either a value or null.
maybe_number = 42;Unwrap with if:
if (maybe_number) |n| {
std.debug.print("{}\n", .{n});
}B.14 Pointers
var x: i32 = 10;
const p: *i32 = &x;&x means “address of x.”
p.* = 20;p.* means “the value pointed to by p.”
B.15 Structs
const Point = struct {
x: i32,
y: i32,
};Create a value:
const p = Point{
.x = 10,
.y = 20,
};Access fields:
std.debug.print("{} {}\n", .{ p.x, p.y });B.16 Methods
const Point = struct {
x: i32,
y: i32,
fn lengthSquared(self: Point) i32 {
return self.x * self.x + self.y * self.y;
}
};Call it:
const n = p.lengthSquared();B.17 Enums
const Direction = enum {
north,
south,
east,
west,
};Use with switch:
switch (dir) {
.north => {},
.south => {},
.east => {},
.west => {},
}B.18 Unions
const Value = union(enum) {
int: i32,
float: f64,
text: []const u8,
};Use with switch:
switch (value) {
.int => |n| std.debug.print("{}\n", .{n}),
.float => |f| std.debug.print("{}\n", .{f}),
.text => |s| std.debug.print("{s}\n", .{s}),
}B.19 Defer
const file = try std.fs.cwd().openFile("data.txt", .{});
defer file.close();defer runs at the end of the current scope.
Use it for cleanup.
B.20 Allocators
const allocator = std.heap.page_allocator;Allocate memory:
const buffer = try allocator.alloc(u8, 1024);
defer allocator.free(buffer);Many Zig APIs ask for an allocator explicitly.
B.21 ArrayList
var list = std.ArrayList(i32).init(allocator);
defer list.deinit();
try list.append(10);
try list.append(20);Read items:
for (list.items) |item| {
std.debug.print("{}\n", .{item});
}B.22 HashMap
var map = std.StringHashMap(i32).init(allocator);
defer map.deinit();
try map.put("one", 1);
try map.put("two", 2);Get a value:
if (map.get("one")) |value| {
std.debug.print("{}\n", .{value});
}B.23 Comptime
fn identity(comptime T: type, value: T) T {
return value;
}Use it:
const a = identity(i32, 10);
const b = identity([]const u8, "hello");comptime means the value is known while the program is being compiled.
B.24 Builtins
Zig builtins start with @.
@import("std")
@sizeOf(i32)
@alignOf(i32)
@typeInfo(i32)
@panic("failed")Common examples:
| Builtin | Use |
|---|---|
@import | Import a file or package |
@sizeOf | Get type size in bytes |
@alignOf | Get type alignment |
@typeInfo | Inspect a type |
@panic | Stop the program |
@compileError | Emit a compile-time error |
B.25 Tests
test "add works" {
try std.testing.expect(add(2, 3) == 5);
}Run tests:
zig test main.zigB.26 Common Format Strings
std.debug.print("{}\n", .{number});
std.debug.print("{s}\n", .{string});
std.debug.print("{any}\n", .{value});| Format | Meaning |
|---|---|
{} | Default formatting |
{s} | String |
{any} | Debug-style formatting |
B.27 Imports
const std = @import("std");
const math = @import("math.zig");If math.zig contains:
pub fn add(a: i32, b: i32) i32 {
return a + b;
}You can call:
const x = math.add(1, 2);B.28 Public Declarations
pub fn run() void {}pub makes a declaration visible outside the file or namespace.
Without pub, the declaration is private to that file or namespace.
B.29 Undefined
var x: i32 = undefined;undefined means the value is not initialized.
Do not read an undefined value. Use it only when you will definitely assign a real value before reading.
B.30 Unreachable
unreachable;Use unreachable to say: execution must never reach this point.
Example:
switch (value) {
0 => {},
1 => {},
else => unreachable,
}Use it carefully. If the program reaches unreachable, that is a bug.
B.31 Small Mental Model
Zig code usually asks you to make things visible:
| Question | Zig usually wants |
|---|---|
| Can this fail? | Put the error in the type |
| Does this allocate? | Pass an allocator |
| Is this nullable? | Use ?T |
| Is this compile-time? | Use comptime |
| Is cleanup needed? | Use defer |
| Is memory shared? | Use pointers or slices explicitly |
The cheat sheet is enough for reading small Zig programs. The details come from the chapters.