不透明型(型エイリアス impl Trait)
不透明型は、特定のトレイト集合のみをインターフェイスとして公開する不透明な型エイリアスを宣言するための構文です。背後にある具体的な型は、不透明型の特定の使用箇所の集合から推論されます。
これは、型エイリアス内で impl Trait を使用することで表現されます。例:
type Foo = impl Bar;
これは Foo という名前の不透明型を宣言します。この型について分かる唯一の情報は、Bar を実装しているということです。したがって、Bar のインターフェイスはいずれも Foo に対して使用できますが、それ以外は使用できません(具体的な型が他のトレイトを実装しているかどうかにかかわらず)。
背後に具体的な型が必要であるため、2025年5月時点()では、その型を不透明型の「定義使用箇所」で不透明型を使用することによって表現できます。
struct Struct;
impl Bar for Struct { /* 処理 */ }
#[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 { /* 処理 */ }
type Foo = impl Bar;
struct Struct;
impl Bar for Struct { /* 処理 */ }
#[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 }
}