mirror of
https://github.com/ziglang/zig.git
synced 2024-11-30 09:02:32 +00:00
e3424332d3
* `doc/langref` formatting * upgrade `.{ .path = "..." }` to `b.path("...")` * avoid using arguments named `self` * make `Build.Step.Id` usage more consistent * add `Build.pathResolve` * use `pathJoin` and `pathResolve` everywhere * make sure `Build.LazyPath.getPath2` returns an absolute path
143 lines
3.4 KiB
Zig
143 lines
3.4 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,
|
|
};
|
|
|
|
// Maybe we want to pass it to OpenGL so we want to be particular about
|
|
// how the bytes are arranged.
|
|
const Point2 = packed struct {
|
|
x: f32,
|
|
y: f32,
|
|
};
|
|
|
|
// Declare an instance of a struct.
|
|
const p = Point{
|
|
.x = 0.12,
|
|
.y = 0.34,
|
|
};
|
|
|
|
// Maybe we're not ready to fill out some of the fields.
|
|
var p2 = Point{
|
|
.x = 0.12,
|
|
.y = undefined,
|
|
};
|
|
|
|
// Structs can have methods
|
|
// Struct methods are not special, they are only namespaced
|
|
// functions that you can call 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;
|
|
}
|
|
};
|
|
|
|
const expect = @import("std").testing.expect;
|
|
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);
|
|
|
|
// you can still instantiate an empty struct
|
|
const does_nothing = Empty{};
|
|
|
|
_ = does_nothing;
|
|
}
|
|
|
|
// struct field order is determined by the compiler for optimal performance.
|
|
// however, you can still calculate a struct base pointer given 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);
|
|
}
|
|
|
|
// You can return a struct from a function. This is how we do generics
|
|
// in Zig:
|
|
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. This means you can
|
|
// do this:
|
|
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);
|
|
}
|
|
|
|
// test
|