Interface
Pattern 1
const std = @import("std");
const Animal = union(enum) {
cat: Cat,
dog: Dog,
pub fn talk(self: Animal) void {
switch (self) {
inline else => |case| case.talk(),
}
}
};
const Cat = struct {
anger_level: usize,
pub fn talk(self: Cat) void {
std.debug.print("[Cat] Meow! (anger Lv {})\n", .{self.anger_level});
}
};
const Dog = struct {
name: []const u8,
pub fn talk(self: Dog) void {
std.debug.print("[Dog] I'm a {s}\n", .{self.name});
}
};
pub fn main() !void {
const cat = Animal{ .cat = .{ .anger_level = 100 } };
cat.talk();
const dog = Animal{ .dog = .{ .name = "lilly" } };
dog.talk();
const animals = [_]Animal{
cat,
dog,
};
for (animals) |a| {
a.talk();
}
}
Pattern 2
const std = @import("std");
const assert = std.debug.assert;
const Animal = struct {
ptr: *anyopaque,
vtab: *const VTab,
const VTab = struct {
talk: *const fn (ptr: *anyopaque) void,
};
pub fn talk(self: Animal) void {
self.vtab.talk(self.ptr);
}
pub fn init(obj: anytype) Animal {
const Ptr = @TypeOf(obj);
const PtrInfo = @typeInfo(Ptr);
assert(PtrInfo == .Pointer); // Must be a pointer
assert(PtrInfo.Pointer.size == .One); // Must be a single-item pointer
assert(@typeInfo(PtrInfo.Pointer.child) == .Struct); // Must point to a struct
const impl = struct {
fn talk(ptr: *anyopaque) void {
const self: Ptr = @ptrCast(@alignCast(ptr));
self.talk();
}
};
return .{
.ptr = obj,
.vtab = &.{
.talk = impl.talk,
},
};
}
};
const Cat = struct {
anger_level: usize,
pub fn talk(self: Cat) void {
std.debug.print("[Cat] Meow! (anger Lv {})\n", .{self.anger_level});
}
};
const Dog = struct {
name: []const u8,
pub fn talk(self: Dog) void {
std.debug.print("[Dog] I'm a {s}\n", .{self.name});
}
};
pub fn main() !void {
var c = Cat{ .anger_level = 100 };
const cat = Animal.init(&c);
cat.talk();
var d = Dog{ .name = "lilly" };
const dog = Animal.init(&d);
dog.talk();
const animals = [_]Animal{
cat,
dog,
};
for (animals) |a| {
a.talk();
}
}
Pattern 3
const std = @import("std");
const assert = std.debug.assert;
const Animal = struct {
ptr: *anyopaque,
talkFnPtr: *const fn (ptr: *anyopaque) void,
pub fn init(obj: anytype, comptime talkFn: fn (ptr: @TypeOf(obj)) void) Animal {
const Ptr = @TypeOf(obj);
const PtrInfo = @typeInfo(Ptr);
assert(PtrInfo == .Pointer); // Must be a pointer
assert(PtrInfo.Pointer.size == .One); // Must be a single-item pointer
assert(@typeInfo(PtrInfo.Pointer.child) == .Struct); // Must point to a struct
const impl = struct {
fn talk(ptr: *anyopaque) void {
const self: Ptr = @ptrCast(@alignCast(ptr));
talkFn(self);
}
};
return .{
.ptr = obj,
.talkFnPtr = impl.talk,
};
}
pub fn talk(self: Animal) void {
self.talkFnPtr(self.ptr);
}
};
const Cat = struct {
anger_level: usize,
pub fn talk(self: *Cat) void {
std.debug.print("[Cat] Meow! (anger Lv {})\n", .{self.anger_level});
}
};
const Dog = struct {
name: []const u8,
pub fn talk(self: *Dog) void {
std.debug.print("[Dog] I'm a {s}\n", .{self.name});
}
};
pub fn main() !void {
var c = Cat{ .anger_level = 100 };
const cat = Animal.init(&c, Cat.talk);
cat.talk();
var d = Dog{ .name = "lilly" };
const dog = Animal.init(&d, Dog.talk);
dog.talk();
const animals = [_]Animal{
cat,
dog,
};
for (animals) |a| {
a.talk();
}
}
Pattern 4
const std = @import("std");
const assert = std.debug.assert;
const Animal = struct {
talkFn: *const fn (ptr: *Animal) void,
pub fn talk(self: *Animal) void {
self.talkFn(self);
}
};
const Cat = struct {
anger_level: usize,
parent: Animal,
pub fn init(anger_level: usize) Cat {
const impl = struct {
pub fn talk(ptr: *Animal) void {
const self: *Cat = @fieldParentPtr("parent", ptr);
self.talk();
}
};
return .{
.anger_level = anger_level,
.parent = .{ .talkFn = impl.talk },
};
}
pub fn talk(self: *Cat) void {
std.debug.print("[Cat] Meow! (anger Lv {})\n", .{self.anger_level});
}
};
const Dog = struct {
name: []const u8,
parent: Animal,
pub fn init(name: []const u8) Dog {
const impl = struct {
pub fn talk(ptr: *Animal) void {
const self: *Dog = @fieldParentPtr("parent", ptr);
self.talk();
}
};
return .{
.name = name,
.parent = .{ .talkFn = impl.talk },
};
}
pub fn talk(self: *Dog) void {
std.debug.print("[Dog] I'm a {s}\n", .{self.name});
}
};
pub fn main() !void {
var cat = Cat.init(100);
cat.talk();
var dog = Dog.init("lilly");
dog.talk();
const animals = [_]*Animal{
&cat.parent,
&dog.parent,
};
// const animals = [_]*Animal{
// @constCast(&Cat.init(100).parent),
// @constCast(&Dog.init("lilly").parent),
// };
for (animals) |a| {
a.talk();
}
}
Pattern 5
const std = @import("std");
const Animal = struct {
pub fn talk(self: anytype) void {
self.talk();
}
};
const Cat = struct {
anger_level: usize,
pub fn talk(self: Cat) void {
std.debug.print("[Cat] Meow! (anger Lv {})\n", .{self.anger_level});
}
};
const Dog = struct {
name: []const u8,
pub fn talk(self: Dog) void {
std.debug.print("[Dog] I'm a {s}\n", .{self.name});
}
};
const Panda = struct {
// error: no field or member function named 'talk' in 't5.Panda'
//
// pub fn talk(_: Panda) void {
// std.debug.print("Hahaha!\n", .{});
// }
};
pub fn main() !void {
const cat = Cat{ .anger_level = 100 };
Animal.talk(cat);
const dog = Dog{ .name = "lilly" };
Animal.talk(dog);
const panda = Panda{};
Animal.talk(panda);
}
無名関数の色々を取得
fn foo(options: anytype) void {
inline for (@typeInfo(@TypeOf(options)).Struct.fields) |field| {
std.debug.print("{s}: {} {}\n", .{ field.name, @field(options, field.name), field.type });
}
}
pub fn main() !void {
const a: u8, const b: u8 = .{ 0, 1 };
// const a, const b = .{ @as(u8, 0), @as(u8, 1) };
foo(.{ .a = a, .b = b });
}
- @ typeInfo(type)はstd.builtin.Typeを返す.
Pointer
test "*const T and *T" {
// immutable
const x: i32 = 1234;
const x_ptr = &x;
try expect(@TypeOf(x_ptr) == *const i32);
// Error
// x_ptr.* = 5678;
try expect(x_ptr.* == 1234);
// mutable
var y: i32 = 1234;
const y_ptr = &y;
try expect(@TypeOf(y_ptr) == *i32);
// Ok
y_ptr.* = 5678;
try expect(y_ptr.* == 5678);
}
test "pointer array access" {
var array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const ptr = &array[2];
try expect(@TypeOf(ptr) == *u8);
try expect(array[2] == 3);
ptr.* += 1;
try expect(array[2] == 4);
// Error
// ptr[1] = 255;
// Ok
const ptr2 = @ptrFromInt(*u8, @intFromPtr(ptr) + @sizeOf(u8));
ptr2.* = 255;
try expect(array[3] == 255);
}
test "*const [N]T and *[N]T" {
// immutable
const x = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const x_ptr = &x;
// Error
// ptr[0] = 255;
try expect(@TypeOf(x_ptr) == *const [10]u8);
try expect(x[0] == 1);
// mutable
var y = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const y_ptr = &y;
// Ok
y_ptr[0] = 255;
try expect(@TypeOf(y_ptr) == *[10]u8);
try expect(y[0] == 255);
}
部分的にzig fmtを無効にする
// zig fmt: off
var arr = [_]u8{ 1, 2 };
// zig fmt: on
var arr1 = [_]u8{ 1, 2 };
Overflow
const std = @import("std");
test "@addWithOverflow" {
const result = @addWithOverflow(@as(u8, std.math.maxInt(u8)), @as(u8, 10));
try std.testing.expectEqual(result, .{ 9, 1 });
}
test "std.math.add" {
const result = std.math.add(u8, std.math.maxInt(u8), 10) catch std.math.maxInt(u8);
try std.testing.expect(result == 255);
}