Hello @arhyth, welcome to the forum 
I am of the opinion that the best way to learn Zig is to read the source code. It’s very approachable compared to many other standard libraries out there, and it will help you rapidly advance in your knowledge. I’ll show you two popular ways to get around the source.
ZLS
if you have not checked out ZLS, please do. It’s an auto-completer that has the ability to jump to definitions. That’s the fastest way to get to the definition of a struct in the source code and read what methods it has.
It’s still being developed but it’s the defacto lsp for Zig at the moment and I find it to be quite approachable and handy. If you need help getting it built and installed, the readme is fairly good (it’s a really quick process). In short:
git clone https://github.com/zigtools/zls
cd zls
zig build -Doptimize=ReleaseSafe
Then move the binary into your path. I’m on ubuntu and I use helix, so for me that was as simple as appending the following line to my .bashrc…
# ZLS support for ZIG LSP in Helix
export PATH="/home/andrew/zls/zig-out/bin:$PATH"
At that point, you’ll have auto-complete and go-to-definition capabilities - if I jump to the struct definition itself, it takes me right to the source on my own computer.
The next best way to learn about methods is to read the associated file on: GitHub - ziglang/zig: General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
The standard library is very easy to read compared to other languages. There are some more difficult patches than others, but we’re always here to help.
For standard utilities, we’ll go to the std
folder: https://github.com/ziglang/zig/tree/master/lib/std
Here, you’ll find the std
import file that gets brought in when you call @import("std")
: https://github.com/ziglang/zig/blob/master/lib/std/std.zig
For the writer, let’s check out the writer file: https://github.com/ziglang/zig/blob/master/lib/std/io/writer.zig
You can search for the fn
keyword and find most of what you’re looking for that way. Here’s all the member functions:
pub fn write(self: Self, bytes: []const u8) Error!usize {
return writeFn(self.context, bytes);
}
pub fn writeAll(self: Self, bytes: []const u8) Error!void {
var index: usize = 0;
while (index != bytes.len) {
index += try self.write(bytes[index..]);
}
}
pub fn print(self: Self, comptime format: []const u8, args: anytype) Error!void {
return std.fmt.format(self, format, args);
}
pub fn writeByte(self: Self, byte: u8) Error!void {
const array = [1]u8{byte};
return self.writeAll(&array);
}
pub fn writeByteNTimes(self: Self, byte: u8, n: usize) Error!void {
var bytes: [256]u8 = undefined;
@memset(bytes[0..], byte);
var remaining: usize = n;
while (remaining > 0) {
const to_write = @min(remaining, bytes.len);
try self.writeAll(bytes[0..to_write]);
remaining -= to_write;
}
}
/// Write a native-endian integer.
pub fn writeIntNative(self: Self, comptime T: type, value: T) Error!void {
var bytes: [@as(u16, @intCast((@as(u17, @typeInfo(T).Int.bits) + 7) / 8))]u8 = undefined;
mem.writeIntNative(std.math.ByteAlignedInt(@TypeOf(value)), &bytes, value);
return self.writeAll(&bytes);
}
/// Write a foreign-endian integer.
pub fn writeIntForeign(self: Self, comptime T: type, value: T) Error!void {
var bytes: [@as(u16, @intCast((@as(u17, @typeInfo(T).Int.bits) + 7) / 8))]u8 = undefined;
mem.writeIntForeign(std.math.ByteAlignedInt(@TypeOf(value)), &bytes, value);
return self.writeAll(&bytes);
}
pub fn writeIntLittle(self: Self, comptime T: type, value: T) Error!void {
var bytes: [@as(u16, @intCast((@as(u17, @typeInfo(T).Int.bits) + 7) / 8))]u8 = undefined;
mem.writeIntLittle(std.math.ByteAlignedInt(@TypeOf(value)), &bytes, value);
return self.writeAll(&bytes);
}
pub fn writeIntBig(self: Self, comptime T: type, value: T) Error!void {
var bytes: [@as(u16, @intCast((@as(u17, @typeInfo(T).Int.bits) + 7) / 8))]u8 = undefined;
mem.writeIntBig(std.math.ByteAlignedInt(@TypeOf(value)), &bytes, value);
return self.writeAll(&bytes);
}
pub fn writeInt(self: Self, comptime T: type, value: T, endian: std.builtin.Endian) Error!void {
var bytes: [@as(u16, @intCast((@as(u17, @typeInfo(T).Int.bits) + 7) / 8))]u8 = undefined;
mem.writeInt(std.math.ByteAlignedInt(@TypeOf(value)), &bytes, value, endian);
return self.writeAll(&bytes);
}
pub fn writeStruct(self: Self, value: anytype) Error!void {
// Only extern and packed structs have defined in-memory layout.
comptime assert(@typeInfo(@TypeOf(value)).Struct.layout != .Auto);
return self.writeAll(mem.asBytes(&value));
}
Again, I strongly urge that you read the standard library. It’s very handy, well written, and (in my opinion) better than the documentation.
I hope some of this helps!