On this page
article
Chapter 6: Structs
Defining and Using Structs
type Point = struct {
x: f32,
y: f32,
};
var p = Point { .x = 1.0, .y = 2.0 };
var p: Point = .{ .x = 1.0, .y = 2.0 }; -- type inferred from context
debug.print("({}, {})\n", .{p.x, p.y});
Field Defaults
type Config = struct {
host: []const u8 = "localhost",
port: u16 = 8080,
timeout: u32 = 30,
debug: bool = false,
};
var cfg = Config { .host = "example.com" };
-- port, timeout, debug use their defaults
Methods
Methods go in impl blocks. Receivers use *self (mutable), *const self (immutable), or self (consuming):
type Rectangle = struct {
width: f32,
height: f32,
};
impl Rectangle {
static fn new(width: f32, height: f32): Self {
return .{ .width = width, .height = height };
}
fn area(*const self): f32 {
return self.width * self.height;
}
fn perimeter(*const self): f32 {
return 2.0 * (self.width + self.height);
}
fn scale(*self, factor: f32) {
self.width *= factor;
self.height *= factor;
}
fn isSquare(*const self): bool {
return self.width = self.height;
}
}
var r = Rectangle::new(3.0, 4.0);
debug.print("area: {}\n", .{r.area()});
r.scale(2.0);
debug.print("scaled area: {}\n", .{r.area()});
Visibility
type BankAccount = struct {
owner: []const u8,
pub readonly balance: f64, -- readable outside, writable inside
pin: u32, -- private
};
impl BankAccount {
static fn new(owner: []const u8, pin: u32): Self {
return .{ .owner = owner, .balance = 0.0, .pin = pin };
}
pub fn deposit(*self, amount: f64) {
self.balance += amount;
}
pub fn withdraw(*self, amount: f64, pin: u32): !void {
if pin != self.pin { return error.WrongPin; }
if amount > self.balance { return error.InsufficientFunds; }
self.balance -= amount;
}
}
Packed and Extern Structs
For hardware registers and C interop:
type Flags = packed struct {
active: u1,
mode: u3,
reserved: u4,
};
type CVec3 = extern struct {
x: f32,
y: f32,
z: f32,
};