Rust で長く開発してきた人が、Zig を実際に触って何を感じたのかを書いた記事だ。単なる印象論ではなく、JSONPath という実用的なライブラリを Rust 版から Zig 版へ移植しながら、IDE 支援、ファイル構成、テスト、関数型っぽい書き方、メモリ管理の手触りを比べている。面白いのは、Zig を持ち上げる記事ではなく、Rust に慣れた目で「どこが気持ちよく、どこが面倒か」をかなり率直に書いている点だと思う。言語の思想の違いが、日々の作業の小さな癖にどう出るのかが見えてくる。
書き手は冒頭で、自分はこの7年間 Rust 開発者としてやってきたと述べる。主に OSS を扱い、Rust の関数型寄りの書き方、たとえば整った関数や表現力のある型に親しんできた。一方で Zig も以前から気になっていた。C の後継候補として、より低レベルで軽く、しかも実用言語として存在感を増しているからだという。昔 C を触っていたこともあり、Rust と比べたらどう感じるかは前から興味があったらしい。
ただし、この記事は Zig の上級者が書いたものではない。最初に触ったプロジェクトがこの移植作業だったので、Zig に慣れた人から見れば素朴で回り道も多いはずだ、と前置きしている。そのうえで、比較の土台をそろえるために、すでに Rust で作ってあったものを Zig で再実装する方針を取った。題材は JSONPath、つまり JSON を問い合わせるための言語で、RFC 9535 に定義されている。Rust 版には jsonpath-rust があり、Zig 版として zig-jsonpath を作った。
最初に驚いたのは IDE 支援の少なさだった。Rust では RustRover や JetBrains 系の環境を使っていたのに、Zig では構文ハイライトと基本的な補完くらいしか頼れない。そこから CLI ベースの作業に戻ることになったが、結果的には build.zig の使い勝手に感心したという。例として、zig build test で全テスト、zig build test -Dfilter="filter match function basic" で特定テスト、zig build test -Ddebug-query=true でデバッグ付き、zig build compliance で互換性テスト、zig build check で単体テストと互換性テストをまとめて走らせる、といった運用を挙げている。これをきっかけに、フル機能の IDE から helix + alacritty + zellij のような構成に移っていったとも書く。
ファイル構成についても、Rust では機能ごとにフォルダを深く切ることが多いのに対し、Zig ではそういう分割をあまり促さないと感じたという。もちろん階層化はできるが、import の手間が増え、「そこまで分けて何が嬉しいのか」と考え直すことになる。結果として、Zig 版は root.zig、parser.zig、model.zig、model_query.zig、query.zig くらいの平たい構成で収まった。Rust 版では parser/ や query/ の下にさらに多くのファイルがぶら下がる形だったので、この差はかなり大きい。
テストも対照的だった。Rust では同じファイルや近い場所に置く inline unit test と、別ディレクトリの integration test を使い分けるのが自然だが、Zig では同じやり方をすると冗長に感じたという。特に今回のようにフラットな構成にすると、model_test のような別ファイルを増やすか、各ファイル内にテストを書くかで迷う。結局は後者を選び、build.zig で明示的に組み込んだ。動き出してしまえば扱いやすいが、Rust のほうがテスト管理は楽だった、と評価している。
記事の後半では、より本質的な違いとして「関数型っぽさ」が崩れていく感覚を説明する。Rust は厳密には imperative language だが、iterator、lazy evaluation、pattern matching、traits、closure など、かなり functional な道具立てを持っている。書き手自身も Haskell や Erlang の経験があり、この JSONPath ライブラリもモナド風のエラー処理、map や flat_map のような変換、イミュータブルな変換、iterator の組み合わせ、宣言的 macro などに寄せて作ってきた。だが Zig では、allocator を前提にした明示的なメモリ管理が中心になるため、どうしても in-place mutation や命令的なループに寄っていく。Rust で reduce や fork を使っていた箇所が、Zig ではカーソル配列を直接書き換える処理になる、という対比を示している。
実際、Zig のコードは所有権の代わりに allocator と init/deinit の責任分担を自分で追いかける必要がある。C よりは安全だが、Rust から来ると「ルールを守る作業を自分で続ける」感覚が強い。記事はここで途切れているが、全体としては、Zig は Rust の代替というより、思想も書き心地もかなり違う言語として立ち上がってきた、という内容になっている。
この話でまず面白いのは、書き手が一番強く記憶したのが言語機能そのものではなく、IDE 支援の薄さだったことだと思う。普通は新しい言語に入ると型推論や文法、エラーメッセージに目が行く。ところがここでは、補完の弱さから CLI での作業に戻り、build.zig を中心にした開発体験がむしろ新鮮だったと振り返っている。これは Zig が「エディタに助けてもらう前提」より「ビルドツールと明示的に対話する前提」に寄っているからではないか。少なくとも Rust の快適さに慣れた人には、最初は後退に見えるはずだ。
ただ、この記事が単純に「Rust の方が快適」と言い切っていないのが重要だ。CLI に寄ったことで、逆に作業の輪郭がはっきりした、と書いている。zig build test のようにタスクを短く呼べるのは、エディタの統合に頼るよりも理解しやすい場面がある。私はここに、Zig の思想がかなり表れていると思う。ツールが全部を面倒見ない代わりに、開発者は何を実行しているのかを自分で把握する。その代わりに、環境を軽く保てる。好き嫌いは分かれるが、少なくとも「書き味」そのものは設計の一部になっている。
Rust では、少し規模が育つとすぐフォルダを切りたくなる。機能ごとに分け、役割ごとに module を整理し、見通しを良くする。ところがこの記事の書き手は、Zig ではその欲求がかなり遅れて現れ、結局最後まで必要にならなかったと述べている。これは単なるディレクトリ設計の話ではない。Zig が「まずは平たく置いて、必要なら後から考えればいい」と背中を押しているように見えるからだ。
私が引っかかったのは、ここで書き手が「フォルダを切りたい衝動」がプロジェクトの実サイズを測る指標になる、と示唆している点だ。つまり、言語のせいで平たくなったのではなく、Zig では平たく置いても破綻しにくい。その結果、初期段階で過剰な分割をしがちな Rust の癖を、別の角度から見直すきっかけになっている。これは言語比較の記事というより、設計習慣の自己点検として読める。実務でも、最初から深いツリーを作るのが正解とは限らない。そこを Zig があえて煽らないのは、案外賢いのではないかと思う。
ここが一番重要な部分だと思う。書き手は、Rust では iterator や combinator を組み合わせることで、かなり宣言的に処理を書いてきた。一方 Zig では、allocator を意識し、配列やカーソルをその場で更新し、ループで回す方が自然になる。技術的にはどちらも成立するが、体感としては Zig のコードのほうが読みづらかったという。これは単に慣れの問題ではないはずだ。関数型のスタイルは、状態の変化を局所化し、データの流れを追いやすくする。Zig の命令的な書き方は、その代わりに「何をいつ書き換えたか」を正確に追う力を要求する。
ただ、私はここを Zig の欠点だけとして受け取るべきではないと思う。Rust の抽象度が高い書き方は美しいが、抽象化の層が増えるぶん、局所的な挙動を追うのに頭を使うこともある。Zig はそこを平らにして、実際のデータ移動とメモリ操作を前面に出す。その分、コードは機械寄りになるが、性能や挙動を読みやすいという別の利点がある。記事の書き手は最終的に Rust のほうが好きそうだが、Zig を通して「自分はどこまで抽象化に依存していたのか」を再確認したのだろう。そこはかなり価値がある体験だと思う。
Zig の allocator 周りの話は、Rust を知っている人ほど刺さるはずだ。C ほど危険ではないが、Rust ほど自動ではない。init/deinit をちゃんと呼び、失敗経路をたどり、誰が解放責任を持つかを毎回考える必要がある。これは「少し面倒」では済まない。呼び出し階層が深くなるほど、責任の所在を見失いやすいからだ。書き手がそれを「tedious」と表現しているのは自然だと思う。
一方で、この面倒さがあるからこそ、Rust の ownership や borrow checker がどれだけ大きな負担を肩代わりしているかも見えてくる。Rust では当たり前に感じていた安全性が、Zig に移ると途端に「自分で律する作業」になる。ここに、Rust と Zig の思想の差がかなりはっきり出ている。私は、Zig が悪いというより、Rust が異常に強力なのだと読んだ。だから Zig を触ると不便に感じるのは当然で、その不便さの中に「C 的な軽さと手動管理を、どこまで現代化できるか」という試みが見える。この記事は、その試みが開発者の身体感覚にどう届くかを、かなり正直に記録している。