Open7

Zig書いてみたい

yaginceyagince

テストの書き方

Rustみたいに同じファイルに書くのが一般的なんだろうか?

fn addFive(x: u32) u32 {
    return x + 5;
}

test "function" {
    try expect(addFive(5) == 10);
}

try って、なんだろうか?

Zig 入門 #8 - Errors - kawaken.dev

try は x catch |err| return err の糖衣構文になります。

なるほど、Rustの ? と似たような雰囲気ですね。

yaginceyagince

Enum

const Suit = enum {
    clubs,
    spades,
    diamonds,
    hearts,
    pub fn isClubs(self: Suit) bool {
        return self == Suit.clubs;
    }
};

test "enum method" {
    try expect(Suit.spades.isClubs() == Suit.isClubs(.spades));
}

このメソッドの書き方おもしろいですねぇ。

ちなみに、これは

test "enum method" {
    const Suit = enum {
        clubs,
        spades,
        diamonds,
        hearts,
        pub fn isClubs(self: Suit) bool {
            return self == Suit.clubs;
        }
    };

    try expect(Suit.spades.isClubs() == Suit.isClubs(.spades));
}

こうするとコンパイルエラーになる

src/main.zig:60:30: error: use of undeclared identifier 'Suit'
        pub fn isClubs(self: Suit) bool {
                             ^~~~

なるほど。

Suit.isClubs(.spades)

この .spades って、 Suit.spades じゃなくていいんですね。
型推論できるから省略できるってことですかね。

yaginceyagince

Struct

特に疑問はないのでスキップ

Unions

const Result = union {
    int: i64,
    float: f64,
    bool: bool,
};

test "simple union" {
    var result = Result{ .int = 1234 };
    result.float = 0.001;
}
main.zig:76:11: 0x1006bd57b in test.simple union (test)
    result.float = 0.001;
          ^

ふむ、なるほど。
これ、どれを持っているか型からわからない?
だとするとどうやって使うんだろうか。
switch?

例えば

const Result = union {
    int: i64,
    float: f64,
    bool: bool,
};

fn hogeResult(r: Result) void {
    std.debug.print("--- {} \n", .{r.bool});
}

test "simple union" {
    const result = Result{ .int = 1234 };
    hogeResult(result);
}

こんな風にすると

panic: access of inactive union field
/src/main.zig:75:37: 0x100ac158f in hogeResult (test)
    std.debug.print("--- {} \n", .{r.bool});
                                    ^

実行時エラーになりますね。

TaggedUnions

この為にタグ付きユニオンというのがあるらしい

const Result = union(enum) {
    int: i64,
    float: f64,
    bool: bool,
};

fn hogeResult(r: Result) void {
    switch (r) {
        .int => |x| {
            std.debug.print("--- {} \n", .{x});
        },
        .float => |x| {
            std.debug.print("--- {} \n", .{x});
        },
        .bool => |x| {
            std.debug.print("--- {} \n", .{x});
        },
    }
}

test "simple union" {
    const result = Result{ .int = 1234 };
    hogeResult(result);
}

こんな風に条件分岐できるようになりました。

yaginceyagince

Allocator & ArrayList

test "ArrayList" {
    const eql = std.mem.eql;
    const ArrayList = std.ArrayList;

    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();

    var list = ArrayList(u8).init(allocator);
    defer list.deinit();
    try list.append('H');
    try list.append('e');
    try list.append('l');
    try list.append('l');
    try list.append('o');
    try list.appendSlice(" World!");

    std.debug.print("--- {s}\n", .{list.items});

    try expect(eql(u8, list.items, "Hello World!"));

    try list.appendSlice("=================================================================================================================================================================================================================================================================================");

    std.debug.print("--- {s}\n", .{list.items});
}
--- Hello World!
--- Hello World!=================================================================================================================================================================================================================================================================================

allocator|zig note

とりあえず、GeneralPurposeAllocatorを使っておいても良さそうなので、そうしてみました。