익명 구조체 리터럴(Anonymous Struct Literals)

익명 구조체 리터럴(Anonymous Struct Literals)

구조체를 만들 때, 그 구조체의 타입을 항상 적어줘야 하는 건 아니에요. Zig는 리터럴의 구조체 타입을 생략하는 걸 허용합니다.

리터럴의 결과가 coerced될 때, 구조체 리터럴은 result location을 그대로 직접 인스턴스화해요. 복사가 일어나지 않습니다. 코드로 볼게요.

출처: Zig Documentation

본문

만약 result location에 타입이 주어져 있다면, 그 타입을 써주는 대신 .으로 시작하는 익명 형태를 그대로 놓을 수 있어요.

const std = @import("std");
const expectEqual = std.testing.expectEqual;

const Point = struct { x: i32, y: i32 };

test "anonymous struct literal" {
    const pt: Point = .{
        .x = 13,
        .y = 67,
    };
    try expectEqual(13, pt.x);
    try expectEqual(67, pt.y);
}
$ zig test test_struct_result.zig
1/1 test_struct_result.test.anonymous struct literal...OK
All 1 tests passed.

pt의 타입을 보면 Point라고 명시되어 있죠. 그래서 리터럴 쪽에서는 .x, .y만 값으로 채워주면 됐어요. 여기서 중요한 건 리터럴이 result location을 직접 인스턴스화한다는 점이에요. 일단 먼저 타입이 명시된 경우를 봤는데, 이번에는 타입이 아예 없는 상황을 살펴볼게요.

구조체 타입은 추론될 수도 있어요. 아래 예시의 result location은 타입을 포함하지 않는데, 이 경우 Zig가 타입을 직접 추론합니다.

const std = @import("std");
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;

test "fully anonymous struct" {
    try check(.{
        .int = @as(u32, 1234),
        .float = @as(f64, 12.34),
        .b = true,
        .s = "hi",
    });
}

fn check(args: anytype) !void {
    try expectEqual(1234, args.int);
    try expectEqual(12.34, args.float);
    try expect(args.b);
    try expectEqual('h', args.s[0]);
    try expectEqual('i', args.s[1]);
}
$ zig test test_anonymous_struct.zig
1/1 test_anonymous_struct.test.fully anonymous struct...OK
All 1 tests passed.

check 함수의 매개변수는 anytype이에요. 그렇기 때문에 .{...} 형태로 전달된 완전히 익명인 구조체가 하나의 타입으로 추론되고, 함수 안에서 args.int, args.float처럼 필드에 접근할 수 있게 됩니다.

더 알아보기