iTranslated by AI
Learning Zig: Practical How-to Notes
Home ⚡ Zig Programming Language
I wanted to build something while learning a new language, and since I've been seeing Zig a lot lately, I thought it would be a good choice. These are the notes I took while experimenting and building with it.
Environment Used
macOS Monterey Version 12.1 Apple M1
Environment Setup
On Mac, it seems it can be installed via Homebrew, so I will try installing it that way.
$ brew install zig
The version installed at this time was 0.9.1.
$ zig version
0.9.1
Hello world
Anyway, let's start by trying Hello world.
First, let's initialize it and try running it as is.
$ zig init-exe
$ zig build run
info: All your codebase are belong to us.
init-exe creates the following:
.
├── build.zig
└── src
└── main.zig
build run performs the build and execution for you. The built executable was created in zig-out/bin/xxxx.
Next, modify src/main.zig as follows to display Hello world.
If Hello, world! is displayed with zig build run, you're good to go.
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
try stdout.print("Hello, {s}!\n", .{"world"});
}
import
To import and call a function defined in another file:
const std = @import("std");
pub fn debug() void {
std.log.debug("funcs#debug call", .{});
}
↑ Add pub to the function you want to call.
const funcs = @import("funcs.zig");
const debug = funcs.debug;
pub fn main() void {
debug();
}
After that, you just need to @import it on the calling side.
Allocator
Types of Allocators
- c_allocator
- Optimal for linking with libc (uses malloc_usable_size)
- raw_c_allocator
- Calls
malloc/freedirectly (does not use malloc_usable_size)
- Calls
- page_allocator
- Calls syscalls directly for every memory allocation and deallocation (Thread-safe and lock-free.)
- HeapAllocator
- Only available on Windows? Uses HANDLE internally
- ArenaAllocator
- Wraps an existing allocator and frees everything at once
- FixedBufferAllocator
- Used when a fixed-length buffer is sufficient
- LogToWriterAllocator
- Outputs logs to a specified Writer when using another allocator
- LoggingAllocator
- Outputs logs to
std.logwhen using another allocator
- Outputs logs to
Basic Usage
const std = @import("std");
const expect = std.testing.expect;
test "allocation" {
const allocator = std.heap.page_allocator;
const memory = try allocator.alloc(u8, 100);
defer allocator.free(memory);
try expect(memory.len == 100);
try expect(@TypeOf(memory) == []u8);
}
When using LoggingAllocator
const std = @import("std");
const loggingAllocator = std.heap.loggingAllocator;
const allocator = loggingAllocator(std.heap.page_allocator).allocator();
// debug: alloc - success - len: 4602, ptr_align: 1, len_align: 1
// debug: free - len: 16384
File Handling
- Opening/Closing a file
const std = @import("std");
pub fn main() !void {
const file_name = "xxxx";
const file = try std.fs.cwd().openFile(fileName, .{});
defer file.close();
}
- Getting file size
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
const file_name = "xxxx";
const file = try std.fs.cwd().openFile(fileName, .{});
defer file.close();
const file_size = try file.getEndPos();
try stdout.print("file size: {d}\n", .{file_size});
}
- Reading a file
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
const file_name = "xxxx";
const file = try std.fs.cwd().openFile(fileName, .{});
defer file.close();
const file_size = try file.getEndPos();
try stdout.print("file size: {d}\n", .{file_size});
var reader = std.io.bufferedReader(file.reader());
var instream = reader.reader();
const allocator = std.heap. page_allocator;
const contents = try instream.readAllAlloc(allocator, file_size);
defer allocator.free(contents);
try stdout.print("read file value: {c}\n", .{contents});
}
When you want to return multiple values together
pub fn getPosition() struct { start: i32, end: i32 } {
const start = 1000;
const end = 2000;
return .{
.start = start,
.end = end
};
}
Return it in a way that bundles it into a struct.
Bad Know-how
Encountered the following error during brew install:
Error: python@3.10: the bottle needs the Apple Command Line Tools to be installed.
You can install them, if desired, with:
xcode-select --install
You can try to install from source with:
brew install --build-from-source python@3.10
Please note building from source is unsupported. You will encounter build
failures with some formulae. If you experience any issues please create pull
requests instead of asking for help on Homebrew's GitHub, Twitter or any other
official channels.
Python 3 is required, so I followed the message and installed the command line tools using xcode-select --install, and the installation was successful.
$ python3 --version
Python 3.9.13
If you have any suggestions like "it would be better to do it this way," I would appreciate your advice!
I'll write another article once I've gathered more notes.
Discussion