Some off-topic i think i won’t use chinese write blog anymore. (Maybe I’ll clarify later.)
I’m a zig noob and have been using it about 2 weeks. I feel that the language fits some of my ideas when i use it, but it still has some problems and it’s not good enough.
The few ways to learn
Normally, when i start learning a new skill, I search for as much information as possible about it. But there is little information about zig that i can get. The official website only introduces basic syntax and provides a list of meta field
. To be honest, I have other language skill so that the basic syntax cost 5 minis for me :)
My first zig project is a simple ini
format. I create this project and write a simple lex program at first time. Write a lex program for ini is easy, eat each char and put the result to the defined token filed.
pub const Token = struct {
kind: Kind
pub const Kind = enum(u8) {
end_of_file,
open_bracket,
close_bracket,
comment,
equal,
string,
whitespace,
break_line,
}
/// ...
}
It’s been fun till here, until i wrote parser. In golang i can create a set of duck type based node just like
type R interface {
Equal() bool
}
type Rule struct {
Data R
}
type AtRule struct {
Token uin8
}
func (*AtRule) Equal() bool {
return true
}
// ... etc
emmm, How can i declare the same describe in zig? BTW zig don’t have any official interface keyword and don’t have trait. So how can i do it? So i searched for related content on Ziggit and i find the answer. (About interface? No i’ll explain later)
We can create a basic node and ohter node like
pub const Rule = struct {
kind: Kind,
pub const AtRule = struct {
base: Rule = .{ .kind = .at_rule }
}
// ...etc
};
The using std.ArrayListUnmanaged
to save us node. we only save the node ptr! I think the problem about save node it’s i’m a gopher …hhh Zig don’t have official interface so my experience is invalid. And we using zig meta program at the stringify time.
Declare a interface
The above section is some of problem i encountered when writing zig programs. This section is a idea about zig interface. Zig’s level of abstraction is just right, but not enough. There’re two ways to descibe interface on zig.
Tagged Unions
const Writer = union(enum) {
file: File,
fn writeAll(self: Writer, data: []const u8) !void {
switch (self) {
.file => |file| return file.writeAll(data),
}
}
};
const File = struct {
fd: os.fd_t,
fn writeAll(self: File, data: []const u8) !void {
_ = try std.os.write(self.fd, data);
}
};
pub fn main() !void {
const file = File{.fd = std.io.getStdOut().handle};
const writer = Writer{.file = file};
try writer.writeAll("hi");
}
vtable
const Writer = struct {
ptr: *anyopaque,
writeAllFn: *const fn (ptr: *anyopaque, data: []const u8) anyerror!void,
fn writeAll(self: Writer, data: []const u8) !void {
return self.writeAllFn(self.ptr, data);
}
};
const File = struct {
fd: os.fd_t,
fn writeAll(ptr: *anyopaque, data: []const u8) !void {
// This re-establishs the type: *anyopaque -> *File
const self: *File = @ptrCast(@alignCast(ptr));
// os.write might not write all of `data`, we should really look at the
// returned value, the number of bytes written, and handle cases where data
// wasn't all written.
_ = try std.os.write(self.fd, data);
}
fn writer(self: *File) Writer {
return .{
// this "erases" the type: *File -> *anyopaque
.ptr = self,
.writeAllFn = writeAll,
};
}
};