Structs
Grouping Data with Structs
Structs are Zig's primary tool for defining custom composite types. They group related data together and can have methods attached to them. If you are coming from C, Zig structs will feel familiar but with significant improvements. If you are coming from an object-oriented language, structs replace classes but without inheritance.
Defining a Struct
const Point = struct {
x: f64,
y: f64,
};
Note the trailing comma after the last field. Zig encourages this style because it makes diffs cleaner when you add or remove fields.
Creating Instances
const p = Point{ .x = 3.0, .y = 4.0 };
Fields are always initialized with the . prefix syntax. There is no positional initialization: you must name every field. This is a deliberate design choice that keeps code readable as structs evolve.
Every starship needs a well-defined blueprint before it leaves the shipyard. A Zig struct is no different --- every field must be accounted for, or the compiler refuses to let it launch.
Default Values
Fields can have default values. Any field with a default can be omitted when constructing the struct:
const Config = struct {
width: u32 = 800,
height: u32 = 600,
fullscreen: bool = false,
};
const c = Config{ .fullscreen = true };
// c.width is 800, c.height is 600
Methods
Methods in Zig are functions declared inside a struct that take self (or *self for mutation) as their first parameter:
const Point = struct {
x: f64,
y: f64,
fn distanceFromOrigin(self: Point) f64 {
return @sqrt(self.x * self.x + self.y * self.y);
}
fn translate(self: *Point, dx: f64, dy: f64) void {
self.x += dx;
self.y += dy;
}
};
Call methods with dot syntax:
var p = Point{ .x = 3.0, .y = 4.0 };
const d = p.distanceFromOrigin(); // 5.0
p.translate(1.0, 1.0); // p is now {4.0, 5.0}
When the method does not need to modify the struct, use self: Point (value). When it does, use self: *Point (pointer).
Namespace Functions
Structs can also contain functions that do not take self. These act as namespace-scoped functions, similar to static methods:
const Point = struct {
x: f64,
y: f64,
fn origin() Point {
return Point{ .x = 0, .y = 0 };
}
};
const p = Point.origin();
Packed Structs
Zig also supports packed struct when you need exact control over memory layout, such as when mapping hardware registers or binary protocols:
const Flags = packed struct {
read: bool,
write: bool,
execute: bool,
_padding: u5 = 0,
};
A packed struct has no padding between fields and guarantees a specific bit layout.
Your Task
Define a Rectangle struct with fields width and height (both f64).
Add two methods:
area(self: Rectangle) f64--- returns the area (width times height).scale(self: *Rectangle, factor: f64) void--- multiplies both width and height by the given factor.