불투명 타입(타입 별칭 impl Trait)
불투명 타입은 특정 트레이트 집합만을 인터페이스로 노출하는 불투명 타입 별칭을 선언하기 위한 구문이며, 그 이면의 구체적인 타입은 불투명 타입이 사용되는 특정 위치들로부터 추론됩니다.
이는 타입 별칭 안에서 impl Trait를 사용하여 표현합니다. 예를 들면 다음과 같습니다.
type Foo = impl Bar;
이는 Foo라는 이름의 불투명 타입을 선언하며, 이 타입에 대해 알려진 정보는 Bar를 구현한다는 것뿐입니다. 따라서 Foo에는 Bar의 인터페이스는 무엇이든 사용할 수 있지만, 그 밖의 것은 사용할 수 없습니다(구체 타입이 다른 트레이트를 구현하는지 여부와 관계없이).
구체적인 배경 타입이 있어야 하므로, ( 2025년 5월 기준) “정의 사용 위치(defining use site)“에서 불투명 타입을 사용하여 그 타입을 표현할 수 있습니다.
struct Struct;
impl Bar for Struct { /* stuff */ }
#[define_opaque(Foo)]
fn foo() -> Foo {
Struct
}
다른 모든 “정의 사용 위치“도 정확히 같은 타입을 만들어야 합니다.
불투명 타입에 대한 타입 별칭을 정의하는 것은 불안정 기능이라는 점에 유의하십시오. 이를 사용하려면 nightly가 필요하며, 파일에는 #![feature(type_alias_impl_trait)] 애너테이션을, 불투명 타입을 구체 타입과 연결하는 메서드에는 #[define_opaque(Foo)] 애너테이션을 달아야 합니다. 전체 예제는 다음과 같습니다.
#![allow(unused)]
#![feature(type_alias_impl_trait)]
fn main() {
trait Bar { /* stuff */ }
type Foo = impl Bar;
struct Struct;
impl Bar for Struct { /* stuff */ }
#[define_opaque(Foo)]
fn foo() -> Foo {
Struct
}
}
정의 사용 위치
현재는 함수의 반환 값만이 불투명 타입의 정의 사용 위치가 될 수 있습니다(그리고 해당 함수의 반환 타입에 불투명 타입이 포함된 경우에만 가능합니다).
불투명 타입의 정의 사용은 불투명 타입 정의의 부모 안에 있는 어떤 코드든 될 수 있습니다. 여기에는 불투명 타입의 모든 형제와 그 형제들의 모든 자식이 포함됩니다.
“타입 시스템이 무엇을 하는지 이해하려다가 실수로 머릿속에서 무한 루프를 돌려 개발자에게 치명적인 뇌 손상을 입히지 않기“를 위한 이니셔티브는 불투명 타입의 자식이 정의 사용 위치가 되는 것을 허용하지 않기로 결정했습니다.
연관 불투명 타입
연관 불투명 타입은 같은 트레이트 impl에 있는 다른 모든 연관 항목이나 그 연관 항목들의 자식에 의해 정의될 수 있습니다. 예를 들면 다음과 같습니다.
trait Baz {
type Foo;
fn foo() -> Self::Foo;
}
struct Quux;
impl Baz for Quux {
type Foo = impl Bar;
fn foo() -> Self::Foo { ... }
}
이 경우에도 nightly와 (앞의 것과는 다른) #![feature(impl_trait_in_assoc_type)] 애너테이션을 사용해야 합니다. 불투명 타입이 (연관 타입 뒤에서) 함수 시그니처에 언급되므로 메서드에 더 이상 #[define_opaque(Foo)]가 필요하지 않다는 점에 유의하십시오. 전체 예제는 다음과 같습니다.
#![feature(impl_trait_in_assoc_type)]
trait Bar {}
struct Zap;
impl Bar for Zap {}
trait Baz {
type Foo;
fn foo() -> Self::Foo;
}
struct Quux;
impl Baz for Quux {
type Foo = impl Bar;
fn foo() -> Self::Foo { Zap }
}