zig/doc/langref/test_structs.zig
Andrew Kelley bfcf18c5a7
Some checks failed
ci / x86_64-linux-debug (push) Has been cancelled
ci / x86_64-linux-release (push) Has been cancelled
ci / aarch64-linux-debug (push) Has been cancelled
ci / aarch64-linux-release (push) Has been cancelled
ci / x86_64-macos-release (push) Has been cancelled
ci / aarch64-macos-debug (push) Has been cancelled
ci / aarch64-macos-release (push) Has been cancelled
ci / x86_64-windows-debug (push) Has been cancelled
ci / x86_64-windows-release (push) Has been cancelled
ci / aarch64-windows (push) Has been cancelled
langref: delete misleading example code about packed structs
2024-11-13 15:35:16 -08:00

127 lines
3.0 KiB
Zig

// Declare a struct.
// Zig gives no guarantees about the order of fields and the size of
// the struct but the fields are guaranteed to be ABI-aligned.
const Point = struct {
x: f32,
y: f32,
};
// Declare an instance of a struct.
const p: Point = .{
.x = 0.12,
.y = 0.34,
};
// Functions in the struct's namespace can be called with dot syntax.
const Vec3 = struct {
x: f32,
y: f32,
z: f32,
pub fn init(x: f32, y: f32, z: f32) Vec3 {
return Vec3{
.x = x,
.y = y,
.z = z,
};
}
pub fn dot(self: Vec3, other: Vec3) f32 {
return self.x * other.x + self.y * other.y + self.z * other.z;
}
};
test "dot product" {
const v1 = Vec3.init(1.0, 0.0, 0.0);
const v2 = Vec3.init(0.0, 1.0, 0.0);
try expect(v1.dot(v2) == 0.0);
// Other than being available to call with dot syntax, struct methods are
// not special. You can reference them as any other declaration inside
// the struct:
try expect(Vec3.dot(v1, v2) == 0.0);
}
// Structs can have declarations.
// Structs can have 0 fields.
const Empty = struct {
pub const PI = 3.14;
};
test "struct namespaced variable" {
try expect(Empty.PI == 3.14);
try expect(@sizeOf(Empty) == 0);
// Empty structs can be instantiated the same as usual.
const does_nothing: Empty = .{};
_ = does_nothing;
}
// Struct field order is determined by the compiler, however, a base pointer
// can be computed from a field pointer:
fn setYBasedOnX(x: *f32, y: f32) void {
const point: *Point = @fieldParentPtr("x", x);
point.y = y;
}
test "field parent pointer" {
var point = Point{
.x = 0.1234,
.y = 0.5678,
};
setYBasedOnX(&point.x, 0.9);
try expect(point.y == 0.9);
}
// Structs can be returned from functions.
fn LinkedList(comptime T: type) type {
return struct {
pub const Node = struct {
prev: ?*Node,
next: ?*Node,
data: T,
};
first: ?*Node,
last: ?*Node,
len: usize,
};
}
test "linked list" {
// Functions called at compile-time are memoized.
try expect(LinkedList(i32) == LinkedList(i32));
const list = LinkedList(i32){
.first = null,
.last = null,
.len = 0,
};
try expect(list.len == 0);
// Since types are first class values you can instantiate the type
// by assigning it to a variable:
const ListOfInts = LinkedList(i32);
try expect(ListOfInts == LinkedList(i32));
var node = ListOfInts.Node{
.prev = null,
.next = null,
.data = 1234,
};
const list2 = LinkedList(i32){
.first = &node,
.last = &node,
.len = 1,
};
// When using a pointer to a struct, fields can be accessed directly,
// without explicitly dereferencing the pointer.
// So you can do
try expect(list2.first.?.data == 1234);
// instead of try expect(list2.first.?.*.data == 1234);
}
const expect = @import("std").testing.expect;
// test