master
1// Declare a struct.
2// Zig gives no guarantees about the order of fields and the size of
3// the struct but the fields are guaranteed to be ABI-aligned.
4const Point = struct {
5 x: f32,
6 y: f32,
7};
8
9// Declare an instance of a struct.
10const p: Point = .{
11 .x = 0.12,
12 .y = 0.34,
13};
14
15// Functions in the struct's namespace can be called with dot syntax.
16const Vec3 = struct {
17 x: f32,
18 y: f32,
19 z: f32,
20
21 pub fn init(x: f32, y: f32, z: f32) Vec3 {
22 return Vec3{
23 .x = x,
24 .y = y,
25 .z = z,
26 };
27 }
28
29 pub fn dot(self: Vec3, other: Vec3) f32 {
30 return self.x * other.x + self.y * other.y + self.z * other.z;
31 }
32};
33
34test "dot product" {
35 const v1 = Vec3.init(1.0, 0.0, 0.0);
36 const v2 = Vec3.init(0.0, 1.0, 0.0);
37 try expect(v1.dot(v2) == 0.0);
38
39 // Other than being available to call with dot syntax, struct methods are
40 // not special. You can reference them as any other declaration inside
41 // the struct:
42 try expect(Vec3.dot(v1, v2) == 0.0);
43}
44
45// Structs can have declarations.
46// Structs can have 0 fields.
47const Empty = struct {
48 pub const PI = 3.14;
49};
50test "struct namespaced variable" {
51 try expect(Empty.PI == 3.14);
52 try expect(@sizeOf(Empty) == 0);
53
54 // Empty structs can be instantiated the same as usual.
55 const does_nothing: Empty = .{};
56
57 _ = does_nothing;
58}
59
60// Struct field order is determined by the compiler, however, a base pointer
61// can be computed from a field pointer:
62fn setYBasedOnX(x: *f32, y: f32) void {
63 const point: *Point = @fieldParentPtr("x", x);
64 point.y = y;
65}
66test "field parent pointer" {
67 var point = Point{
68 .x = 0.1234,
69 .y = 0.5678,
70 };
71 setYBasedOnX(&point.x, 0.9);
72 try expect(point.y == 0.9);
73}
74
75// Structs can be returned from functions.
76fn LinkedList(comptime T: type) type {
77 return struct {
78 pub const Node = struct {
79 prev: ?*Node,
80 next: ?*Node,
81 data: T,
82 };
83
84 first: ?*Node,
85 last: ?*Node,
86 len: usize,
87 };
88}
89
90test "linked list" {
91 // Functions called at compile-time are memoized.
92 try expect(LinkedList(i32) == LinkedList(i32));
93
94 const list = LinkedList(i32){
95 .first = null,
96 .last = null,
97 .len = 0,
98 };
99 try expect(list.len == 0);
100
101 // Since types are first class values you can instantiate the type
102 // by assigning it to a variable:
103 const ListOfInts = LinkedList(i32);
104 try expect(ListOfInts == LinkedList(i32));
105
106 var node = ListOfInts.Node{
107 .prev = null,
108 .next = null,
109 .data = 1234,
110 };
111 const list2 = LinkedList(i32){
112 .first = &node,
113 .last = &node,
114 .len = 1,
115 };
116
117 // When using a pointer to a struct, fields can be accessed directly,
118 // without explicitly dereferencing the pointer.
119 // So you can do
120 try expect(list2.first.?.data == 1234);
121 // instead of try expect(list2.first.?.*.data == 1234);
122}
123
124const expect = @import("std").testing.expect;
125
126// test