Fields are selected with the dot operator.
point.x
point.yThe expression on the left must be a struct, union, enum, or pointer to one of those types. The name on the right selects a field or declaration.
Begin with a small example.
const std = @import("std");
const Point = struct {
x: i32,
y: i32,
};
pub fn main() void {
const point = Point{
.x = 4,
.y = 7,
};
std.debug.print("{d}\n", .{point.x});
std.debug.print("{d}\n", .{point.y});
}The output is:
4
7point.x reads the field named x from point.
A field may be assigned if the struct value is mutable.
const std = @import("std");
const Counter = struct {
value: u32,
};
pub fn main() void {
var counter = Counter{
.value = 0,
};
counter.value = 10;
std.debug.print("{d}\n", .{counter.value});
}The output is:
10If counter were declared with const, the assignment would fail.
const counter = Counter{
.value = 0,
};
counter.value = 10;Zig would report that the value is constant.
Struct assignment copies the entire value.
const std = @import("std");
const Point = struct {
x: i32,
y: i32,
};
pub fn main() void {
var a = Point{
.x = 1,
.y = 2,
};
var b = a;
b.x = 99;
std.debug.print("a.x = {d}\n", .{a.x});
std.debug.print("b.x = {d}\n", .{b.x});
}The output is:
a.x = 1
b.x = 99Changing b does not change a. The assignment copied the struct value.
A pointer may also be used to access fields.
const std = @import("std");
const Point = struct {
x: i32,
y: i32,
};
pub fn main() void {
var point = Point{
.x = 3,
.y = 5,
};
const ptr = &point;
ptr.x = 100;
std.debug.print("{d}\n", .{point.x});
}The output is:
100Here ptr is a pointer to Point.
Notice that the code uses:
ptr.xnot:
(*ptr).xZig automatically dereferences pointers when selecting fields. This removes much of the punctuation common in C programs.
Field access works through nested structs.
const std = @import("std");
const Size = struct {
width: u32,
height: u32,
};
const Window = struct {
title: []const u8,
size: Size,
};
pub fn main() void {
const window = Window{
.title = "editor",
.size = Size{
.width = 800,
.height = 600,
},
};
std.debug.print("{d} x {d}\n", .{
window.size.width,
window.size.height,
});
}The output is:
800 x 600Each dot selects one field.
A field may itself be another struct, array, slice, or pointer. Field access works the same way in each case.
Struct declarations can also contain constants and functions.
const Vec2 = struct {
x: f32,
y: f32,
const zero = Vec2{
.x = 0,
.y = 0,
};
};The constant is accessed with:
Vec2.zeroThis also uses the dot operator.
Functions inside a struct are accessed the same way.
const std = @import("std");
const Counter = struct {
value: u32,
pub fn reset(counter: *Counter) void {
counter.value = 0;
}
};
pub fn main() void {
var counter = Counter{
.value = 25,
};
Counter.reset(&counter);
std.debug.print("{d}\n", .{counter.value});
}The output is:
0Counter.reset selects the function declaration named reset from the namespace of Counter.
A field name must exist.
point.zThis is an error because Point has no field named z.
Zig checks field names at compile time. Misspelled names are reported immediately.
Exercises.
7-5. Define a Person struct with fields name and age. Print both fields.
7-6. Make a mutable struct value and change one field.
7-7. Create a nested struct representing a rectangle with a position and size.
7-8. Copy a struct into another variable. Change one field in the copy and verify that the original value does not change.