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);
}
// https://github.com/ziglang/zig/blob/master/lib/std/Random.zig
pub fn init(pointer: anytype) Animal {
const Ptr = @TypeOf(pointer);
assert(@typeInfo(Ptr) == .pointer); // Must be a pointer
assert(@typeInfo(Ptr).pointer.size == .one); // Must be a single-item pointer
assert(@typeInfo(@typeInfo(Ptr).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 = pointer,
.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();
}
}
Register as a new user and use Qiita more conveniently
- You get articles that match your needs
- You can efficiently read back useful information
- You can use dark theme