🍒
Zig で環境変数を型安全に管理
はじめに
先週、私は Zig の comptime を学び、struct-env というライブラリを作成しました。
このライブラリを使用すると、環境変数を自動的に対応する構造体のフィールドに逆シリアル化することができます。以下は使用例です。
main.zig
const std = @import("std");
const struct_env = @import("struct-env");
const MyEnv = struct {
home: []const u8,
foo: ?[]const u8,
bar: []const u8 = "bar",
};
pub fn main() !void {
const allocator = std.heap.page_allocator;
const env = try struct_env.fromEnv(allocator, MyEnv);
defer struct_env.free(allocator, env);
std.debug.print("HOME is {s}\n", .{env.home});
std.debug.print("FOO is {any}\n", .{env.foo == null});
std.debug.print("BAR is {s}\n", .{env.bar});
}
実行後、HOME
、FOO
、BAR
の環境変数が自動的に構造体に注入されます。
$ zig build run
HOME is /home/guest
FOO is true
BAR is bar
Zig の comptime
ここからは、Zig の comptime に関する知識を共有します。
まず最初に、
-
@TypeOf
は値の型を取得するためのものです。 -
@typeName
は型の名前を取得するためのものです。
const std = @import("std");
const testing = std.testing;
const T = struct {
a: i32,
};
pub fn main() !void {
const t = T{ .a = 1 };
try testing.expectEqual(T, @TypeOf(t));
try testing.expect(std.mem.eql(u8, "main.T", @typeName(T)));
}
-
std.meta.Child
を使用すると、複合型の子型を取得することができます。
try testing.expectEqual(std.meta.Child(?T), T);
try testing.expectEqual(std.meta.Child([]const T), T);
-
@typeInfo
、型の詳細情報を取得することができます。
pub fn printInfo(comptime T: type) void {
switch (@typeInfo(T)) {
.Struct => print("Struct", .{}),
.Optional => print("Optional", .{}),
.Bool => print("Bool", .{}),
.aa => {},
else => {},
}
return;
}
@typeInfo
の結果は、以下の場所で定義されています:
次に、フィールドのデフォルト値を取得する方法です。
@typeInfo
を使用すると、構造体の情報を取得できます。その中の field
属性を使用すると、構造体内の各フィールドの情報を取得できます。StructField
の定義は以下のようになります
この構造体には、デフォルト値への型消去ポインタが含まれています。*anyopaque
は、C言語 のvoid
ポインタのようなものです。対応する型に変換するためには、@ptrCast
を使用する必要があります。
pub fn main() !void {
const T = struct {
a: i32 = 10,
};
const field = @typeInfo(T).Struct.fields[0];
if (field.default_value) |default_value| {
const anyopaque_pointer: *anyopaque = @constCast(default_value);
const value = @ptrCast(*field.type, @alignCast(field.alignment, anyopaque_pointer)).*;
std.debug.print("default value is {d}\n", .{value});
}
}
おわりに
Zig のドキュメントは十分な内容ではありません。reddit や Stack Overflow の親切な人々が私を多く助けてくれました。本当に感謝しています。
Discussion