| name | zig |
| description | Use when writing Zig code. Contains Zig 0.15 API changes and patterns. |
Zig 0.15 API Reference
CRITICAL: API Changes from 0.14
ArrayList (now unmanaged by default)
In 0.15, std.ArrayList is now the unmanaged version (previously ArrayListUnmanaged). It doesn't store the allocator - you pass it to each method.
// OLD (0.14)
var list = std.ArrayList(T).init(allocator);
defer list.deinit();
try list.append(item);
// NEW (0.15) - std.ArrayList is unmanaged
var list: std.ArrayList(T) = .empty;
defer list.deinit(allocator);
try list.append(allocator, item);
// If you need the managed version (stores allocator):
var list = std.array_list.Managed(T).init(allocator);
defer list.deinit();
try list.append(item);
Note: std.ArrayListUnmanaged is deprecated and now just an alias for std.ArrayList.
stdout/stderr
// OLD (0.14)
const stdout = std.io.getStdOut().writer();
try stdout.print("{s}\n", .{msg});
// NEW (0.15)
const stdout = std.fs.File.stdout();
try stdout.writeAll(msg);
try stdout.writeAll("\n");
// For formatted output, use bufPrint
var buf: [256]u8 = undefined;
const line = try std.fmt.bufPrint(&buf, "{d}: {s}\n", .{num, str});
try stdout.writeAll(line);
File writer
// OLD (0.14)
const file = try std.fs.createFileAbsolute(path, .{});
var writer = file.writer();
try writer.print("{s}\n", .{data});
// NEW (0.15)
const file = try std.fs.createFileAbsolute(path, .{});
var buf: [4096]u8 = undefined;
const line = try std.fmt.bufPrint(&buf, "{s}\n", .{data});
try file.writeAll(line);
No bufferedReader
// OLD (0.14)
var buf_reader = std.io.bufferedReader(file.reader());
var reader = buf_reader.reader();
while (reader.readUntilDelimiterOrEof(&buf, '\n')) |line| { ... }
// NEW (0.15) - Read whole file, split manually
var buf: [65536]u8 = undefined;
const len = try file.readAll(&buf);
var it = std.mem.splitScalar(u8, buf[0..len], '\n');
while (it.next()) |line| { ... }
Common Patterns
Reading a file
fn readFile(allocator: std.mem.Allocator, path: []const u8) ![]u8 {
const file = try std.fs.openFileAbsolute(path, .{});
defer file.close();
var buf: [4096]u8 = undefined;
const len = try file.readAll(&buf);
if (len == 0) return error.EmptyFile;
// Trim trailing newlines
var end = len;
while (end > 0 and (buf[end - 1] == '\n' or buf[end - 1] == '\r')) end -= 1;
const result = try allocator.alloc(u8, end);
@memcpy(result, buf[0..end]);
return result;
}
Environment variables
const home = std.posix.getenv("HOME") orelse return error.NoHome;
const pwd = std.posix.getenv("PWD") orelse ".";
Path operations
const path = try std.fs.path.join(allocator, &.{ dir, filename });
defer allocator.free(path);
const parent = std.fs.path.dirname(path);
const basename = std.fs.path.basename(path);
const resolved = try std.fs.path.resolve(allocator, &.{ base, relative });
Check if path is directory
fn isDirectory(path: []const u8) bool {
const stat = std.fs.cwd().statFile(path) catch return false;
return stat.kind == .directory;
}
Command line args
const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
// args[0] is program name, args[1..] are arguments
String operations
// Check prefix
if (std.mem.startsWith(u8, str, "prefix")) { ... }
// Split
var it = std.mem.splitScalar(u8, str, '|');
while (it.next()) |part| { ... }
// Index of
if (std.mem.indexOf(u8, haystack, needle)) |pos| { ... }
// Equal
if (std.mem.eql(u8, a, b)) { ... }
// To lowercase (in place with buffer)
var buf: [256]u8 = undefined;
for (str, 0..) |c, i| buf[i] = std.ascii.toLower(c);
const lower = buf[0..str.len];
Timestamps
const now = std.time.timestamp(); // i64 seconds since epoch
Sorting
const Context = struct { now: i64 };
const ctx = Context{ .now = std.time.timestamp() };
std.mem.sort(T, items, ctx, struct {
fn lessThan(c: Context, a: T, b: T) bool {
return a.value < b.value;
}
}.lessThan);
Build Commands
zig build-exe src/main.zig
zig build-exe src/main.zig -O ReleaseSmall -fstrip -fsingle-threaded --name output
rm -f output.o