mcpField
Z
zig-0-17

zig-0-17

github.com/zigcc開発5345 回インストール3 週間前に更新
リポジトリ

zig-0-17 について

zig-0-17は、Zig 0.17.0を扱う開発者向けのプログラミングガイドです。このバージョン固有の言語と標準ライブラリの変更を、移行例とともに説明し、ローカル環境のドキュメントやソースを先に確認する方法も示します。

主な機能

  1. 01Zig 0.17.0の変更リファレンス
  2. 02破壊的変更の移行例
  3. 03組み込み機能と構文の更新
  4. 04標準ライブラリAPIの変更
  5. 05ローカルドキュメント優先の方針

活用シーン

  1. 01Zig 0.16.xコードの移行
  2. 02更新された組み込み機能の確認
  3. 03標準ライブラリ呼び出しの修正
  4. 04ローカル文書に基づくAPI確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/zigcc/skills --skill zig-0-17

インストール後、Claude Code で/zig-0-17を入力して読み込まれたか確認します。

同梱ファイルscripts/check-zig-version.sh

詳細

Zig 0.17.0 プログラミングガイド

バージョンの対象範囲:Zig 0.17.0(安定版)に固定されています。 リリースノート:https://ziglang.org/download/0.17.0/release-notes.html

Zig 0.17.0 では、言語の安定性が 1.0 に向けてさらに高められています。主な変更点には、@intFromEnum/@enumFromInt を @backingInt/@fromBackingInt に置き換えたこと、型リフレクション(std.lang.Type)とコンテナーの組み込み機能を構造体配列(SoA)形式に移行したこと、配列の乗算構文 ** を削除して @splat に置き換えたこと、DebugAllocator をスレッドセーフな SafeAllocator に置き換えたこと、fmt.allocPrint を mem.Allocator に移したこと、C 変換を外部パッケージに分離したこと、ビルドシステムを Configurer と Maker の独立したプロセスに分割し、細粒度のキャッシュ汚染追跡を導入したことなどがあります。


まずローカルドキュメントを確認

zig env を実行してローカルのインストールパスを確認してください。パスをハードコードしないでください。

  • 言語リファレンス:<lib_dir>/../doc/langref.html
  • 標準ライブラリのソース:正確なシグネチャは .std_dir 以下のソースファイルを確認してください。
  • 標準ライブラリのドキュメント:zig std を実行すると、ローカルのドキュメント HTTP サーバーが起動します。

オンラインで検索する前に、必ずローカルのドキュメントまたはソースを確認してください。


クイックリファレンス:主な破壊的変更

旧(0.16.x)新(0.17.0)備考
@intFromEnum(val)@backingInt(val)ビットパックおよびタグ付きユニオンでも使用可能
@enumFromInt(val)@fromBackingInt(val)戻り値の型は推論されます。不正な値は安全性チェックの対象です
[1]T{val} ** len@splat(val)配列の乗算 ** は削除されました。@splat を使用してください
@bitCast(extern_struct_val)@ptrCast(&val).* または extern union@bitCast は extern struct/extern union に対して使用できません
void{}{}構文 void{} は削除されました
errdefer |err| { ... }ヘルパー関数に切り出し、catch |err| を使用errdefer でのエラーキャプチャは削除されました
i0u0プリミティブ整数型 i0 は削除されました
@hasDecl(同じファイル内の非公開宣言にも true を返す)pub 宣言に対してのみ true を返すファイル間で動作が統一されました
@cImport({...})b.dependency("translate_c", .{}) + Translator@cImport は削除されました。C トランスレーターはパッケージに移されました
std.heap.DebugAllocatorstd.heap.SafeAllocatorスレッドセーフで、再利用せず、リークと破損を検出します
std.heap.StackFallbackAllocator(N)std.heap.BufferFirstAllocator.init(buf, fallback)comptime サイズではなく、バッファーを明示的に指定します
std.fmt.allocPrint(arena, ...)arena.print(...)/allocator.print(...)std.mem.Allocator に移されました
list.getLastOrNull()list.last()?T を返します
list.getLast()list.last().?.? で非 null をアサートします。新しい list.lastPtr() は ?*T を返します
std.zon.parse.fromSliceAllocstd.zon.parse.fromSlice(T, .{ ... })構造体引数を使用します。新しく updateFromSlice が追加されました
std.bit_set.IntegerBitSetstd.bit_set.Integer同様に Array、Static、Dynamic も変更されました。.empty/.full
@typeInfo(S).@"struct".fieldsfield_names、field_types、field_attrs型リフレクションは構造体配列(SoA)形式に書き換えられました
@Struct(引数 7 個)@Struct(layout, BackingInt, names, types, attrs)引数は 5 個です。@Union は 5 個、@Enum は 4 個です
std.lang.OptimizeModestd.lang.Optimizeタグは小文字になりました:.debug、.safe、.fast、.small
@import("builtin").cpu / os / abi@import("builtin").target.cpu / os / abi.target 経由でアクセスします
b.build_root(Directory)b.root(Cache.Path)パスの表現が変更されました
if (b.args) |args| run.addArgs(args);run.addPassthruArgs()引数の変更があっても configure キャッシュを純粋に保ちます
b.findProgram(...)b.findProgramLazy(...)遅延解決により configure キャッシュの汚染を防ぎます

言語の変更点

1. @backingInt と @fromBackingInt による enum 変換ビルトインの置き換え

@intFromEnum と @enumFromInt は非推奨になりました(#35966)。代わりに @backingInt と @fromBackingInt を使用してください。

  • @backingInt は次の型で使用できます。
    • すべての enum 型。
    • 明示的なバッキング整数を持つビットパック(packed struct / packed union)。
    • タグ付き union 型(アクティブなタグのバッキング整数を返します)。
  • @fromBackingInt は変換先の型を推論します(任意の enum、または明示的なバッキング整数を持つビットパック)。バッキング型に一致する整数を受け取り、enum のタグ値を安全性チェック付きで検証します。
  • 空の enum では、バッキング整数として noreturn を宣言する必要があります(例:enum(noreturn) {})。
  • zig fmt は古い @intFromEnum および @enumFromInt の呼び出しを自動的に更新します。
const Status = enum(u8) {
    ok = 0,
    err = 1,
};

const status: Status = .ok;
// Convert enum to backing integer
const raw: u8 = @backingInt(status);

// Convert backing integer to enum (type is inferred from context)
const restored: Status = @fromBackingInt(raw);

// Helper function to query backing integer type:
const TagInt = std.meta.BackingInt(Status); // u8
2. @bitCast のセマンティクス:論理ビット表現のみ

Zig 0.17.0 では、@bitCast が値の論理ビット表現を再解釈するように再定義され、エンディアンに完全に依存しなくなりました。

  • 使用できる型:void、bool、整数(comptime_int を除く)、浮動小数点数(comptime_float を除く)、整数をバッキング型とする enum(T)、packed struct(T)、packed union(T)、およびそれらの配列/ベクトル。
  • 禁止:extern struct と extern union は @bitCast に渡せなくなりました。
  • extern struct のメモリ表現を型パニングするには、@ptrCast または extern union を使用してください。
const TwoBytes = extern struct {
    b0: u8,
    b1: u8,
};

test "type pun extern struct in 0.17" {
    const bytes: TwoBytes = .{ .b0 = 0x12, .b1 = 0xAB };

    // OLD (0.16): const int: u16 = @bitCast(bytes); // COMPILE ERROR in 0.17

    // NEW (0.17): Use pointer cast
    const int_ptr: *align(1) const u16 = @ptrCast(&bytes);
    const int: u16 = int_ptr.*;
    _ = int;
}
3. 配列の乗算 ** を削除 — @splat を使用

繰り返し構文 [1]u8{0} ** N は削除されました。代わりに @splat を使用してください。

// OLD (0.16)
var buf = [1]u8{0} ** 1024;
const arr = [1]f32{1.5} ** 4;

// NEW (0.17)
var buf: [1024]u8 = @splat(0);
const arr: [4]f32 = @splat(1.5);
4. @divCeil を追加

整数除算を正の無限大($+\infty$)方向に丸めます。@divTrunc、@divFloor、@divExact を補完するものです。

try std.testing.expectEqual(2, @divCeil(5, 3));
try std.testing.expectEqual(-1, @divCeil(-5, 3));
5. @hasDecl は公開(pub)宣言のみを調べる

以前は、同じソースファイル内から呼び出した場合、@hasDecl(T, name) は非公開の宣言に対しても true を返していました。現在は呼び出し元のコンテキストにかかわらず、pub 宣言のみを厳密にチェックします。

const Foo = struct {
    pub const public_val = 1;
    const private_val = 2;
};

// In 0.17:
@hasDecl(Foo, "public_val") == true;
@hasDecl(Foo, "private_val") == false; // Always false even within the same file
6. コンパイル時に長さが決まるスライスの間接参照と配列への型強制

長さがコンパイル時に決まるスライスを、直接間接参照したり、配列ポインターに型強制したりできるようになりました。

const slice: []const u16 = &.{ 1, 2, 3 };
const array: [3]u16 = slice.*;               // Valid in 0.17
const array_ptr: *const [3]u16 = slice;      // Valid in 0.17
7. 構文の削除:void{}、errdefer |err|、i0
  • void{} を削除:void{} を {} に置き換えてください。
  • errdefer |err| を削除:errdefer でエラーを捕捉できなくなりました。内部関数に切り分けるか、catch |err| で処理してください。
    // OLD:
    // errdefer |err| std.log.err("failed: {s}", .{@errorName(err)});
    
    // NEW:
    fn run() void {
        runInner() catch |err| {
            std.log.err("failed: {s}", .{@errorName(err)});
        };
    }
    fn runInner() !void { ... }
    
  • i0 を削除:i0 の使用箇所はすべて u0 に置き換えてください。
  • グローバルリンケージの整理:std.lang.GlobalLinkage の internal と link_once が削除されました。link_once には weak を使用し、internal の代わりに @export を省略してください。
8. @cImport を削除 — 外部 translate_c パッケージ

@cImport は完全に削除されました。また、std.Build.Step.TranslateC は非推奨となり、公式の外部パッケージが推奨されるようになりました。

zig fetch --save git+https://codeberg.org/ziglang/translate-c

build.zig では次のようにします。

const std = @import("std");
const Translator = @import("translate_c").Translator;

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const translate_c_dep = b.dependency("translate_c", .{});
    const translator: Translator = .init(translate_c_dep, .{
        .c_source_file = b.path("src/c.h"),
        .target = target,
        .optimize = optimize,
    });
    translator.linkSystemLibrary("glfw3", .{});

    const exe = b.addExecutable(.{
        .name = "myapp",
        .root_module = b.createModule(.{
            .root_source_file = b.path("src/main.zig"),
            .target = target,
            .optimize = optimize,
            .imports = &.{
                .{ .name = "c", .module = translator.mod },
            },
        }),
    });
    b.installArtifact(exe);
}

標準ライブラリの変更

1. std.heap.SafeAllocator(DebugAllocator に代わるもの)

std.heap.DebugAllocator は非推奨になりました。代わりに std.heap.SafeAllocator を使用してください。

  • スレッドセーフ:外部ロックなしで並行処理できます。
  • 安全性の保証:deinit() 時にリークが報告されます。不正な解放、操作の競合、バッファーの上書きは、AllocFooter のチェックサムによってパニックまたはセグメンテーションフォールトを引き起こします。
  • メモリを再利用しない:解放済みメモリを再利用せず、解放後使用バグを検出します。
const std = @import("std");

test "SafeAllocator usage" {
    var gpa: std.heap.SafeAllocator = .init(std.heap.page_allocator, .{});
    defer {
        const leaks = gpa.deinit();
        if (leaks != 0) @panic("Memory leak detected!");
    }
    const allocator = gpa.allocator();

    const slice = try allocator.alloc(u32, 16);
    defer allocator.free(slice);
}
2. BufferFirstAllocator(再構成された StackFallbackAllocator)

StackFallbackAllocator(N) は std.heap.BufferFirstAllocator に置き換えられました。コンパイル時のバッファーサイズを宣言するのではなく、明示的なバッファースライスを渡してください。

var stack_buf: [256]u8 = undefined;
var bfa: std.heap.BufferFirstAllocator = .init(&stack_buf, gpa);
const allocator = bfa.allocator();

// Allocations small enough will use stack_buf; spills fallback to gpa.
3. std.fmt.allocPrint に代わる mem.Allocator.print

allocPrint は std.mem.Allocator のインスタンスメソッドになりました。

// OLD (0.16)
const str = try std.fmt.allocPrint(allocator, "{s}={d}", .{ key, val });

// NEW (0.17)
const str = try allocator.print("{s}={d}", .{ key, val });
// For null-terminated strings:
const zstr = try allocator.printSentinel("{s}={d}", .{ key, val }, 0);
4. ArrayList の更新:last()、last().?、lastPtr()
  • getLastOrNull() は非推奨です $\rightarrow$ last()(?T を返します)を使用してください。
  • getLast() は非推奨です $\rightarrow$ last().? を使用してください。
  • lastPtr() を追加 $\rightarrow$ ?*T を返します。
var list = try std.ArrayList(u32).initCapacity(allocator, 8);
defer list.deinit(allocator);

try list.append(allocator, 42);

if (list.last()) |val| {
    // val == 42
}
const non_null = list.last().?;

if (list.lastPtr()) |ptr| {
    ptr.* += 1;
}
5. std.zon.parse の再設計

std.zon は設定構造体を受け取り、アリーナからメモリを確保するようになりました。

const Config = struct {
    host: []const u8,
    port: u16,
};

var diag: std.zon.parse.Diagnostics = undefined;
const parsed = try std.zon.parse.fromSlice(Config, .{
    .gpa = gpa,
    .arena = arena,
    .source = zon_text,
    .diagnostics = &diag,
});

// For in-place field updates:
// std.zon.parse.updateFromSlice(&config, .{ ... });
6. std.bit_set の名称変更

標準ビットセットのバリアントが最新化されました。

  • IntegerBitSet $\rightarrow$ std.bit_set.Integer
  • ArrayBitSet $\rightarrow$ std.bit_set.Array
  • StaticBitSet $\rightarrow$ std.bit_set.Static
  • DynamicBitSetUnmanaged $\rightarrow$ std.bit_set.Dynamic
  • DynamicBitSet(管理型)$\rightarrow$ std.bit_set.DynamicManaged(非推奨)
  • initEmpty() / initFull() $\rightarrow$ .empty / .full 宣言リテラルを使用します。
7. 型リフレクション:std.lang.Type の構造体配列(SoA)

std.lang.Type の型検査フィールドが、構造体の配列(fields: []Field)から配列構造体(field_names、field_types、field_attrs)に移行しました。

fn printFieldNames(comptime T: type) void {
    const info = @typeInfo(T).@"struct";
    inline for (info.field_names, info.field_types, info.field_attrs) |name, field_type, attrs| {
        _ = field_type;
        _ = attrs;
        std.debug.print("Field: {s}\n", .{name});
    }
}
型を作成する組み込み関数の更新:
  • @Struct(layout, BackingInt, field_names, field_types, field_attrs)(7 個から 5 個のパラメーターに変更)
  • @Union(layout, tag_type, field_names, field_types, field_attrs)(5 個のパラメーター)
  • @Enum(tag_type, mode, field_names, field_values)(4 個のパラメーター)

ヒント:フィールド属性のデフォルト値には &@splat(.{}) を使用します。

const MyStruct = @Struct(
    .auto,
    null,
    &.{"x", "y"},
    &.{i32, i32},
    &@splat(.{}),
);
8. std.lang.Optimize(タグを小文字化)

std.lang.OptimizeMode の名称が std.lang.Optimize に変更されました。

  • タグ:.debug、.safe、.fast、.small
  • std.debug.runtime_safety の代わりに std.lang.Optimize.runtimeSafety(mode) を使用します。
9. その他の非推奨化と整理
  • @import("builtin"):.cpu、.os、.abi、.object_format は非推奨です $\rightarrow$ .target.cpu、.target.os、.target.abi、.target.ofmt を使用します。
  • std.builtin は非推奨となり、std.lang が推奨されます。
  • std.DoublyLinkedList.pop $\rightarrow$ popLast
  • std.gpu $\rightarrow$ std.spirv
  • std.ascii.indexOfIgnoreCase* $\rightarrow$ std.ascii.findIgnoreCase*
  • Uri は net.HostName から切り離されました $\rightarrow$ std.Io.net.HostName.fromUri(uri, &buf) を使用します。
  • mem.eql と mem.findDiff は、float スライスのポインターが等しい場合に早期終了しなくなりました(NaN を正しく処理します)。

ビルドシステムとツールチェーン

1. Maker プロセスと Configurer プロセスの分離

zig build はプロジェクトの構成とビルドの実行を分離します。

  • Configurer:build.zig を評価し、ビルドグラフを表すバイナリ形式に変換します。
  • Maker:タスクの評価、パッケージの取得、ステップの実行を担う、再利用可能なプリコンパイル済みバイナリです。
  • 後続の実行を高速化し、IDE やツール向けの Build Server Protocol (--listen=-) を支えます。
2. 構成キャッシュのポイズニング

build.zig のロジックが、キャッシュシステムで追跡できない副作用を生むと、構成キャッシュがポイズニングされ、次回の実行時に全面的な再評価が強制されます。

  • b.findProgram(...) は構成時に即座に PATH を検索します $\rightarrow$ キャッシュをポイズニングします。
  • 推奨:b.findProgramLazy(...) は LazyPath を返します $\rightarrow$ 純粋で、キャッシュをポイズニングしません。
  • ファイル/ディレクトリの依存関係を明示的に宣言してキャッシュの純粋性を保つには:
    b.dependOnFileContents(path);
    b.dependOnFileMetadata(path);
    b.dependOnDirectoryContents(dir_path);
    b.dependOnDirectoryMetadata(dir_path);
    
  • CLI フラグで上書きします:--cache-poison=pure(デフォルト)、poisoned、disallowed、または ignored。
3. Run ステップ:Passthru 引数

build.zig で b.args を調べないでください。addPassthruArgs() を使用します。

// OLD (0.16)
if (b.args) |args| {
    run_cmd.addArgs(args);
}

// NEW (0.17)
run_cmd.addPassthruArgs();

zig build run -- arg1 arg2 で CLI 引数を変更しても、構成キャッシュが無効にならなくなります!

4. システムライブラリと pkg-config

Zig 0.17 では、Module.linkSystemLibrary はデフォルトで pkg-config を使用します。

module.linkSystemLibrary("foo", .{});

.pc ファイルを含まない、Windows の bcrypt や ws2_32 などのプラットフォーム提供ライブラリでは、pkg-config を明示的に無効にします。

module.linkSystemLibrary("bcrypt", .{
    .use_pkg_config = .no,
});

この場合も、ライブラリは名前でリンクされます。Zig が pkg-config を呼び出さないようにするだけです。

5. ビルドルートとパスのオプション
  • b.build_root(Directory) $\rightarrow$ b.root(Cache.Path)。
  • Step.Options:ファイルとディレクトリを区別します。
    • addOptionPath(name, path)(ファイルのみ)
    • addOptionPathDirectory(name, path)(ディレクトリのみ)
    • addOptionPathUntracked(name, path)(依存関係の追跡対象から除外)
  • b.pathList(&.{ "src", "test" }) は、fmt ステップ用の []const LazyPath を生成します。
    const fmt_step = b.addFmt(.{
        .paths = b.pathList(&.{ "src", "build.zig" }),
    });
    
  • b.dependencyLazy は error.LazyDependencyNeeded を返すことがあります。pub fn build(b: *std.Build) !void では、次のようにします。
    const dep = try b.dependencyLazy("my_dep", .{});
    

Zig 0.17.0 でよく使われるイディオム

標準的なプロジェクトのエントリーポイント(Juicy Main)
const std = @import("std");

pub fn main(init: std.process.Init) !void {
    const io = init.io;
    const gpa = init.gpa;
    const arena = init.arena.allocator();

    // Print to stdout
    try std.Io.File.stdout().writeStreamingAll(io, "Running on Zig 0.17.0!\n");

    // Dynamic formatted string
    const greeting = try gpa.print("Hello, {s}!", .{"World"});
    defer gpa.free(greeting);

    // Read CLI args
    const args = try init.minimal.args.toSlice(arena);
    for (args, 0..) |arg, i| {
        std.log.info("arg[{d}]: {s}", .{ i, arg });
    }
}
テストでの SafeAllocator によるメモリー管理
const std = @import("std");

test "data processing test" {
    var gpa: std.heap.SafeAllocator = .init(std.heap.page_allocator, .{});
    defer {
        const leaks = gpa.deinit();
        std.debug.assert(leaks == 0);
    }
    const allocator = gpa.allocator();

    var list = try std.ArrayList(u32).initCapacity(allocator, 4);
    defer list.deinit(allocator);

    try list.append(allocator, 100);
    try std.testing.expectEqual(@as(u32, 100), list.last().?);
}

よくあるエラーメッセージと修正方法(0.17)

エラーメッセージ根本原因解決方法
error: cannot @bitCast from 'extern struct'@bitCast は extern struct/extern union を受け付けません@ptrCast(&val).* を使用するか、extern union を使用します
error: expected 5 arguments, found 7 on @StructSoA の更新で @Struct のパラメーター数が減りましたデフォルト値/アラインメント/comptime を field_attrs スライスにまとめます
error: no member named 'getLastOrNull' in 'ArrayList'メソッド名が変更されましたlist.last() を使用します
error: no member named 'allocPrint' in 'std.fmt'関数が mem.Allocator に移動しましたallocator.print(...) を直接呼び出します
error: expected type 'std.lang.Optimize', found 'std.builtin.OptimizeMode'OptimizeMode の名前が変更され、タグが小文字になりましたstd.lang.Optimize.debug/.safe/.fast/.small を使用します
error: no member named 'initEmpty' in 'std.bit_set'初期化子の構文が更新されましたstd.bit_set.Integer.empty または宣言リテラル .empty を使用します
error: 'errdefer' cannot capture error|err| キャプチャ構文が削除されましたロジックをヘルパー関数にまとめ、catch |err| を使用します
error: cannot multiply array types with '**'配列の乗算が削除されました[1]T{val} ** N を @splat(val) に置き換えます

移植方法(0.16 → 0.17)

  1. 最初に zig fmt を実行します: zig fmt は @intFromEnum $\rightarrow$ @backingInt と @enumFromInt $\rightarrow$ @fromBackingInt を自動的に移行します。
  2. 配列の繰り返しを修正します: ** による配列の乗算を検索し、@splat(...) に置き換えます。
  3. @bitCast を確認します: extern struct または extern union に @bitCast が使われていないことを確認します。ポインターへの @ptrCast に置き換えるか、extern union にリファクタリングします。
  4. fmt.allocPrint を更新します: std.fmt.allocPrint(alloc, ...) を alloc.print(...) に変更します。
  5. ArrayList の呼び出しを更新します: getLastOrNull() を last() に、getLast() を last().? に置き換えます。
  6. ビルドシステムを移行します:
    • build.zig で、run_cmd.addArgs(args) の条件分岐を run_cmd.addPassthruArgs() に置き換えます。
    • パスが make 時にのみ必要な場合は、b.findProgram を b.findProgramLazy に置き換えます。
    • b.build_root を b.root に置き換えます。
    • b.pathList(...) を使って、フォーマット処理のステップで使用する paths を更新します。
    • C 変換を使用する場合は、build.zig.zon に translate_c 依存関係を追加し、Translator を使用します。
  7. テストを検証します: zig build test を実行して正常にコンパイルできることを確認し、SafeAllocator でメモリーリークがゼロであることを検証します。

コメント