test_structs.zig (3075B) - Raw
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. 4 const Point = struct { 5 x: f32, 6 y: f32, 7 }; 8 9 // Declare an instance of a struct. 10 const 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. 16 const 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 34 test "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. 47 const Empty = struct { 48 pub const PI = 3.14; 49 }; 50 test "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: 62 fn setYBasedOnX(x: *f32, y: f32) void { 63 const point: *Point = @fieldParentPtr("x", x); 64 point.y = y; 65 } 66 test "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. 76 fn 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 90 test "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 124 const expect = @import("std").testing.expect; 125 126 // test