はじめに
こんにちは。最近 Zig に嵌ってます。
Zig でも無名関数っぽいものはできますが、クロージャ(Closure)はないようなので、研究してみました。
動作を確認した Zig のバージョンは 0.14.0 です。
ソース
const std = @import("std");
fn foo(x: i32) fn (y: i32) i32 {
return struct {
var _x: i32 = x;
pub fn closure(y: i32) i32 {
_x *= y;
return _x;
}
}.closure;
}
pub fn main() void {
{
const f = foo(2);
std.debug.print("{d}, {d}, {d}\n", .{f(4), f(2), f(10)});
}
{
const f = foo(3);
std.debug.print("{d}, {d}, {d}\n", .{f(4), f(2), f(10)});
}
{
std.debug.print("{d}\n", .{foo(5)(10)});
}
}
分かったこと
キャプチャー対象となる変数(ここでは x
)をどこに保存するかが問題となりますが、ヒープに保存するのが本手であると思います。
しかし、ヒープを使うとガベージコレクションなどを実装しない限り後始末の問題が残りますので、ここでは、コンパイル時に領域が確保されるいわゆる static
(≒ global
)にキャプチャーした変数を保存しています。
そのため、複数の Closure を同時に使用した場合の動作に注意が必要となりますので、これでも Closure といえるかどうかは微妙なところです。
キャプチャー対象となる変数がヒープ上にある場合はいずれにせよ後始末が必要ですから、アリーナなどを使ってまとめてヒープ管理するようなものであればできそうではあります。
最後に
Zig は初心者ですので間違いがあったら指摘していただけると大変ありがたいです。
それではみなさん楽しい Zig ライフを。