@field
@field
보통 구조체의 필드에 접근할 때는 .x처럼 점 표기법이나 p.x = ... 같은 문법을 써요. 그런데 필드 이름을 컴파일 타임에 결정되는 문자열로 가져와야 할 때가 있어요. 예를 들어 설정 파일이나 데이터 구조를 이름 기반으로 다루는 경우죠. 이럴 때 쓰는 게 @field 내장 함수예요. @field는 컴파일 타임 문자열을 받아서 **필드 접근(field access)**을 수행해요. 필드뿐 아니라 **선언(declaration)**에도 동작한다는 점이 포인트예요.
본문
@field는 컴파일 타임 문자열을 기준으로 필드 접근을 수행해요. 구조체의 필드와 선언 모두에 동작합니다.
@field(lhs: anytype, comptime field_name: []const u8) (field)
파일 이름을 문자열로 받아 해당 필드에 접근하는 예시를 볼게요.
const std = @import("std");
const expectEqual = std.testing.expectEqual;
const Point = struct {
x: u32,
y: u32,
pub var z: u32 = 1;
};
test "field access by string" {
var p = Point{ .x = 0, .y = 0 };
@field(p, "x") = 4;
@field(p, "y") = @field(p, "x") + 1;
try expectEqual(4, @field(p, "x"));
try expectEqual(5, @field(p, "y"));
}
test "decl access by string" {
try expectEqual(1, @field(Point, "z"));
@field(Point, "z") = 2;
try expectEqual(2, @field(Point, "z"));
}
$ zig test test_field_builtin.zig
1/2 test_field_builtin.test.field access by string...OK
2/2 test_field_builtin.test.decl access by string...OK
All 2 tests passed.
먼저 @field(p, "x")를 보면, lhs로 넘긴 값 p의 "x"라는 이름의 필드에 접근해서 값을 읽거나 쓸 수 있어요. 첫 번째 테스트에서는 @field(p, "x") = 4처럼 왼쪽 값(l-value)으로 써서 p.x에 4를 넣고, 다시 @field(p, "y")로 p.x의 값을 읽어와 5를 만들어 넣었죠. 문자열로 이름을 주고도 일반적인 필드 접근과 똑같이 읽기·쓰기가 모두 가능하다는 걸 보여줘요.
두 번째 테스트가 핵심 차이를 보여주는데요, Point 자체를 lhs로 넘겨요. Point에는 x, y 필드뿐 아니라 pub var z라는 선언(declaration) 도 있어요. @field(Point, "z")는 이 선언에 이름으로 접근해서 값을 읽고(1 확인), 다시 2로 바꾸기도 해요. 즉 @field는 필드만이 아니라 구조체 안의 선언까지 문자열 기반으로 접근할 수 있다는 뜻이에요.
이렇게 이름이 컴파일 타임 상수로만 주어져야 한다는 조건이 중요해요. field_name이 comptime 인자라서, 런타임에 바뀌는 임의의 문자열로는 쓸 수 없어요. 이름 기반 다형성이나 메타 프로그래밍을 구현할 때 유용한 도구예요.
더 알아보기
- @fieldParentPtr — 필드 포인터로부터 부모 구조체·유니온 포인터 얻기
- struct — 구조체 정의와 필드
- comptime — 컴파일 타임 평가,
@field의 이름 인자가 평가되는 시점