Structs

Structs are one way to define custom types in Zig:

const std = @import("std");
const print = std.debug.print;

const Color = struct {
    red: f32,
    green: f32,
    blue: f32,
};

pub fn main() void {
    var c = Color{
        .red = 1.0,
        .green = 0.0,
        .blue = 1.0,
    };

    print("{} {} {}\n", .{ c.red, c.blue, c.green });

    c.red = 0.5;
    c.green = 0.25;

    print("{}\n", .{c});
}
$ zig run structs.zig 
1 1 0
.{ .red = 0.5, .green = 0.25, .blue = 1 }

A struct definition can contain functions and constants:

const std = @import("std");
const print = std.debug.print;

const Color = struct {
    red: f32,
    green: f32,
    blue: f32,
    alpha: f32 = 1.0,

    // An init function is often used as a constructor.
    fn init(red: f32, green: f32, blue: f32) Color {
        return .{
            .red = red,
            .green = green,
            .blue = blue,
        };
    }

    const WHITE = Color.init(0.0, 0.0, 0.0);

    // Defining a method on Color:
    fn isTransparent(self: Color) bool {
        return self.alpha == 0.0;
    }

    fn makeTransparent(self: *Color) void {
        self.alpha = 0.0;
    }
};

pub fn main() void {
    const w = Color.WHITE;
    print("white: {}\n", .{w});
    print("transparent? {}\n", .{
        // Calling the method:
        w.isTransparent()});
    print("\n", .{});

    var r = Color.init(1.0, 0.3, 0.3);
    r.makeTransparent();
    print("r: {}\n", .{r});
    print("transparent? {}\n", .{r.isTransparent()});
    print("\n", .{});

    // With a pointer to a struct, we can still access
    // fields and methods with .
    const ptr = &r;
    print("green: {}\n", .{ptr.green});
    print("transparent?: {}\n", .{ptr.isTransparent()});
}
$ zig run structs-2.zig 
white: .{ .red = 0, .green = 0, .blue = 0, .alpha = 1 }
transparent? false

r: .{ .red = 1, .green = 0.3, .blue = 0.3, .alpha = 0 }
transparent? true

green: 0.3
transparent?: true

Next example: Tuples.