opaque - 내부 구조를 드러내지 않는 타입

opaque - 내부 구조를 드러내지 않는 타입

C 코드와 맞닿을 때, 그 구조체가 실제로 어떻게 생겼는지는 몰라도 그냥 '포인터만 건네주면 되는' 상황이 있어요. 하지만 타입을 아무렇게나 쓰면 실수로 엉뚱한 걸 넘겨버릴 수도 있고요. Zig에서는 이럴 때 opaque라는 타입으로 '이건 서로 다른 타입이다'라는 사실만 알려줄 수 있어요.

출처: Zig Documentation

본문

opaque {}는 크기와 정렬이 알려져 있지 않지만(0은 아니에요) 새로운 타입을 선언해요. 이 안에는 struct, union, enum처럼 선언(declaration)을 담을 수 있어요.

이 타입은 주로 C 코드와 상호작용할 때 타입 안전성을 위해 사용해요. 구조체의 세부 내용까지 드러내지 않는 C 코드를 다룰 때가 대표적인 경우죠. 예시를 볼게요.

const Derp = opaque {};
const Wat = opaque {};

extern fn bar(d: *Derp) void;
fn foo(w: *Wat) callconv(.c) void {
    bar(w);
}

test "call foo" {
    foo(undefined);
}

DerpWat은 둘 다 빈 opaque 타입이고, 서로 다른 타입으로 취급돼요. foo*Wat를 받는데, bar를 부르는 자리에서 *Derp가 필요하죠. 여기서 bar(w)처럼 *Wat를 그대로 넘기면 컴파일러가 타입이 맞지 않는다고 잡아줘요.

$ zig test test_opaque.zig
/home/ci/work/zig-bootstrap/zig/doc/langref/test_opaque.zig:6:9: error: expected type '*test_opaque.Derp', found '*test_opaque.Wat'
    bar(w);
        ^
/home/ci/work/zig-bootstrap/zig/doc/langref/test_opaque.zig:6:9: note: pointer type child 'test_opaque.Wat' cannot cast into pointer type child 'test_opaque.Derp'
/home/ci/work/zig-bootstrap/zig/doc/langref/test_opaque.zig:2:13: note: opaque declared here
const Wat = opaque {};
            ^~~~~~~~~
/home/ci/work/zig-bootstrap/zig/doc/langref/test_opaque.zig:1:14: note: opaque declared here
const Derp = opaque {};
             ^~~~~~~~~
/home/ci/work/zig-bootstrap/zig/doc/langref/test_opaque.zig:4:18: note: parameter type declared here
extern fn bar(d: *Derp) void;
                 ^~~~~
referenced by:
    test.call foo: /home/ci/work/zig-bootstrap/zig/doc/langref/test_opaque.zig:10:8

에러와 note를 보면 핵심이 확 드러나요. "expected type '*test_opaque.Derp', found '*test_opaque.Wat'" — *Wat*Derp로 바꿔 쓸 수 없다고 하는 거죠. 두 타입이 둘 다 opaque {}로 만들어진 빈 껍데기라 생김새는 같아도, 이름이 다르면 서로 다른 타입이라는 걸 컴파일 단계에서 확실히 지켜줘요. opaque는 그래서 "내부는 모르지만 여기 다른 것과는 구분되는 별개의 타입"이라는 안전망을 만들어 주는 도구예요.

더 알아보기

  • C 코드에서 구조체 세부를 감추고 불투명 포인터(opaque pointer)로 다룰 때 opaque 타입이 쓰여요.
  • opaque 안에도 선언을 넣을 수 있으니, 타입과 함께 그 타입에 어울리는 상수나 함수를 함께 묶어둘 수 있어요.
  • struct, union, enum 문서에서 타입 선언의 기본 형태를 함께 보면 opaque의 위치가 더 잘 그려져요.