Anonymous Structs
const std = @import("std");
const expect = std.testing.expect;
fn describe(point: struct { x: i32, y: i32 }) i32 {
return point.x + point.y;
}
test "anonymous struct literal" {
// The type is inferred from context, so the name need not be written.
try expect(describe(.{ .x = 1, .y = 2 }) == 3);
}
test "tuples are anonymous structs with numeric fields" {
const tuple = .{ @as(u8, 1), true, @as(f32, 2.5) };
try expect(tuple.len == 3);
try expect(tuple[0] == 1);
try expect(tuple[1] == true);
}
test "tuples hold mixed types" {
const pair = .{ @as(u32, 7), "seven" };
try expect(pair[0] == 7);
try expect(std.mem.eql(u8, pair[1], "seven"));
}
test "this is how format arguments work" {
// `.{ a, b }` in a print call is just a tuple; the format string is
// checked against it at compile time.
var buf: [32]u8 = undefined;
const text = try std.fmt.bufPrint(&buf, "{s}={d}", .{ "x", 42 });
try expect(std.mem.eql(u8, text, "x=42"));
}.{ ... } is a struct literal whose type comes from context. When the target
type is known (a parameter, a field, a return type), the name is redundant:
describe(.{ .x = 1, .y = 2 });
Tuples
Leave out the field names and you get a tuple: a struct whose fields are
numbered. Tuples have .len, support indexing, and may mix types freely:
const tuple = .{ @as(u8, 1), true, @as(f32, 2.5) };
tuple[0]; // 1
tuple.len; // 3
Index with a comptime-known constant: tuple[i] for a runtime i cannot work,
because each element has its own type. Walk them with
inline for.
This is what format arguments are
std.fmt.bufPrint(&buf, "{s}={d}", .{ "x", 42 });
That second argument is just a tuple. There is no varargs mechanism in Zig:
print takes one value that happens to be a struct, walks it with inline for,
and checks it against the format string at compile time. A mismatched {d} is
a compile error, not a runtime surprise.