Zig で簡単な JSON パーサを書いてみた。
はじめに
最近あたらしいプログラミング言語を覚えてないなと思ったので、Zig を触ってみる事にした。
と言っても随分前から気になっていて ziglings もやっていたんだけど、ちょっと飽きてしまった。
JSON パーサ
昔から新しいプログラミング言語で遊ぶ時には JSON パーサか Lisp インタプリタを書く様にしているけど、今回は JSON パーサにした。
※ 実用的な物ではありません
といっても単純にパースして Value 構造体に納めるまでしか実装してないし、シリアライザも無い。 気が向いたら続きを作る。
触感
ziglings を触っていたのである程度、触感はあったのだけど JSON パーサを実装してみて Zig がだいたいどんな言語なのか分かってきた。一言で言うなれば
「Rust ぽいC言語」
別の言い回しをするなら
「Result と Optional のあるC言語」
といった所だと思う。
個人的な Zig のオススメどころ
何がすごいって、ReleaseSmall だと思う。fizzbuzz をC言語と Rust、それと Zig でビルドしてみた。
言語 | オプション | サイズ(b) |
---|---|---|
C言語 | -Os | 42496 |
Rust | strip | 129536 |
Zig | -Drelease-small | 8192 |
コード
#include <stdio.h>
int
main(int argc, char* argv[]) {
int i;
for (i = 1; i <= 100; i++) {
if (i % 15 == 0) puts("FizzBuzz");
else if (i % 15 == 0) puts("FizzBuzz");
else if (i % 3 == 0) puts("Fizz");
else if (i % 5 == 0) puts("Buzz");
else printf("%d\n", i);
}
return 0;
}
fn main() {
let mut x = 1;
while x <= 100 {
if x % 15 == 0 {
println!("FizzBuzz");
} else if x % 3 == 0 {
println!("Fizz");
} else if x % 5 == 0 {
println!("Buzz");
} else {
println!("{}", x);
}
x += 1;
}
}
const std = @import("std");
fn fizzbuzz(writer: anytype, i: u32) !void {
if (i % 15 == 0) {
try writer.print("{s}\n", .{"FizzBuzz"});
} else if (i % 3 == 0) {
try writer.print("{s}\n", .{"Fizz"});
} else if (i % 5 == 0) {
try writer.print("{s}\n", .{"Buzz"});
} else {
try writer.print("{}\n", .{i});
}
}
pub fn main() anyerror!void {
const stdout = std.io.getStdOut().writer();
var i: u32 = 1;
while (i <= 100) : (i += 1) {
try fizzbuzz(stdout, i);
}
}
ちょっとビックリする。サイズだけの話でもないが、個人的な感想で間違いを恐れずに言ってしまうと、Linux に組み込むなら正直 Rust より Zig の方が向いてると思ってる。(個人的な感想)
また LLVM で最適化されたコードを吐くのでケースによっては Rust より速い事もある。
https://programming-language-benchmarks.vercel.app/rust-vs-zig
さらに wasm と連携する仕組みもそこそこ整ってきていると思っていて、現在では簡単に wasm を生成できる様になっている。
先日見付けたのだけど、3年前に既に Zig から DOM を生成し、イベントハンドラを書いて wasm 側から alert を表示するサンプルも動いている。
https://github.com/shritesh/zig-wasm-dom
wasm に限らずだがクロスコンパイルに長けている。通常 GitHub Actions では amd64 のバイナリしか生成する事ができず、QEMU を使って頑張ったりするのだけど、setup-zig で Zig コンパイラをインストールし、環境変数 CC
を設定してあげれば amd64 上で arm64 のバイナリを簡単に生成できる。とても便利。先日、deno の拡張を作ったけど、arm64 バイナリは Zig で生成している。
おわりに
Zig で JSON パーサを書いて遊んでみました。めっちゃ速い JavaScript ランタイムの bun も Zig で書かれているし、これから Zig が目立ち始めるんじゃないかと思っています。
追記
Lisp インタプリタも書いてみたのでこちらもどうぞ。
Discussion