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