Structs
12.1 Defining and Using Structs
Methods are just namespaced functions: p.length() ≡ Point.length(p).
Decl literals (0.14+): const p: Point = .init(3, 4); or .origin resolve against the result type.
const Point = struct {
x: f32,
y: f32 = 0, // default field value
pub const origin = Point{ .x = 0, .y = 0 }; // declaration (namespaced constant)
pub fn init(x: f32, y: f32) Point { // "constructor" convention
return .{ .x = x, .y = y };
}
pub fn length(self: Point) f32 { // method (self by value)
return @sqrt(self.x * self.x + self.y * self.y);
}
pub fn scale(self: *Point, k: f32) void { // mutating method (self by pointer)
self.x *= k;
self.y *= k;
}
};
var p = Point.init(3, 4);
p.scale(2);
std.debug.print("{d}\n", .{p.length()});
const q: Point = .{ .x = 1 }; // anonymous struct literal with an inferred type
const r = Point.origin;
_ = .{ q, r };12.2 Struct Memory Layout
struct (auto) The compiler may reorder fields for optimal size. No guaranteed layout.
extern struct C ABI layout (field order kept, C alignment rules) packed struct
Bit-packed with no padding. Fields can be arbitrary-width ints. Backed by an integer.
const Flags = packed struct(u8) { // exactly 8 bits
read: bool,
write: bool,
exec: bool,
_padding: u5 = 0,
};
const f = Flags{ .read = true, .write = false, .exec = true };
const raw: u8 = @bitCast(f);
_ = raw;
const CHeader = extern struct {
magic: u32,
version: u16,
flags: u16,
};12.3 Anonymous Structs and Tuples
const anon = .{ .name = "Ana", .age = 30 }; // anonymous struct literal
const tuple = .{ 1, "two", 3.0 }; // tuple (fields named 0, 1, 2)
std.debug.print("{s} {d}\n", .{ anon.name, tuple[0] });
const Pair = struct { i32, []const u8 }; // tuple type
const pr: Pair = .{ 1, "x" };
_ = pr;
inline for (tuple) |item| std.debug.print("{any}\n", .{item});12.4 Files as Structs
// Vec2.zig: a file with top-level fields IS a struct type
x: f32,
y: f32,
const Vec2 = @This();
pub fn add(a: Vec2, b: Vec2) Vec2 {
return .{ .x = a.x + b.x, .y = a.y + b.y };
}// main.zig
const Vec2 = @import("Vec2.zig");
const v = Vec2.add(.{ .x = 1, .y = 2 }, .{ .x = 3, .y = 4 });12.5 @This() and Self-Reference
const Node = struct {
value: i32,
next: ?*Node = null, // self-referential via pointer
const Self = @This();
pub fn append(self: *Self, n: *Node) void { self.next = n; }
};12.6 Struct Equality and Printing
Structs don't support ==. Compare fields, or use std.meta.eql(a, b).
Printing: {any} prints a debug representation. Define a format method for custom formatting (Module 20).
12.7 Field Parent Pointer
This is the basis of intrusive data structures (e.g., std.DoublyLinkedList in 0.15) and interface patterns.
const Outer = struct { id: u32, inner: Inner };
fn fromInner(inner_ptr: *Inner) *Outer {
return @fieldParentPtr("inner", inner_ptr); // recover the containing struct
}