klknn log / posts / tags / works / feed / src
最近システム系の言語として、Cコンパイラを内蔵したり話題になっている zig 言語。簡単なプログラムを書きながら入門しています。仕様はミニマルな感じですが、なかなかユニークな言語です。
現時点で最新の0.6.0を想定。公式にドキュメントがない部分も多いので今後変わる可能性が高い。この辺は新参の言語ということで愛嬌だが、RustやD言語のようなレベルを想定すると驚く。ただ一貫した思想のあるミニマリストな言語なので意外となんとかなる。
公式サイト からビルド済みバイナリをDLしてパスを通すだけ。CPUはx86と各種arm系、OSはlinuxにwindows、freebsdもあるすごい。
wget https://ziglang.org/download/0.6.0/zig-linux-x86_64-0.6.0.tar.xz
tar xvf zig-linux-x86_64-0.6.0.tar.xz
export PATH=$(pwd)/zig-linux-x86_64-0.6.0:$PATH
同じページに Language Reference と Standard Library Documentation がある。これらと github のコードがほぼ全ての情報源である。とりあえず最初の Hello world くらいはやっとくと雰囲気つかめる。
エディタがLSPに対応していれば zls をいれると定義元にジャンプしたりドキュメント読んだり、はかどります。 zig fmt
というコマンドでフォーマットできるのですが、若干クセがあり、例えば構造体などの最後の要素に "," がないと一行にフォーマットされる挙動に最初戸惑いました。このへんの挙動は このテスト群 を見ればわかります。
まずは簡単なプロジェクトの作成から。本稿の情報はまったくドキュメントがなく、全部 build.zig を読んで得たもので、間違っているかもしれない。
mkdir foo
cd foo
zig init-exe
ライブラリを作るときは init-lib
これでこんなファイルが生成される
const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("foo", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.install();
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}
たぶん普通のアプリをかくなら malloc とかで libc は必要。この辺、デフォルトで何もついてないのが真のシステム用言語という感じがしますね。
const exe = b.addExecutable("foo", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.linkSystemLibrary("c"); // -lc がビルドオプションに追加される
コマンドラインから zig build run
で実行。
D言語みたいにテスト用の構文がある。これはとても便利で、REPL的に使って言語の確認をしたり便利。
const std = @import("std");
fn f() {
return 1;
}
test "f" {
std.debug.assert(f() == 1);
}
正直、これで良いのかわかっていませんが、動いている・ちゃんと失敗するのでとりあえず。
const test_step = b.step("test", "Test the app");
const main_test = b.addTest("src/main.zig");
main_test.linkSystemLibrary("c");
test_step.dependOn(&main_test.step); // 同じように複数ファイル追加も可能
さっしの通り b.step(コマンド名, 説明)
で定義したコマンドを zig build コマンド名
で動かせるようだ。かなり汎用。
union(enum)
タグ付きユニオンというやつ。システム系でよくあるパターンを楽に。?T
。ポインタのoptionalはポインタと同じサイズになるのも嬉しい。!T
や try
式で、明示的にerrorやoptional投げるところがわかる。。defer
D言語でいう scope(exit)
で、初期化と最終化を並べてかける。でも変なところもある、for 文が配列専用で、while文が従来のfor文みたいな役割になってるのは慣れない。公式のコーディングスタイルも独特である(変数と名前空間はsnake_case、関数はcamelCase、型と型関数はTitleCase)。とはいえ慣れの問題といえばそう。
勉強用に、とりあえず小さいJVMみたいなやつ書いてます。CIとかも設定してる。
https://github.com/klknn/zigjvm
今後、とりあえずCとの連携とか調べて、BLASとか数値計算用のライブラリでも作ろうかな。それかvector型があるのでそれを試すか。