Swift Type ErasureでProtocolを使いやすく!初心者向け型消去の完全ガイド
生徒
「SwiftのProtocolを使うと便利って聞いたんですけど、難しい言葉が多くてよく分かりません。Type ErasureとかPATってなんですか?」
先生
「いい質問ですね。SwiftではProtocol(プロトコル)と呼ばれる“約束事”を使ってコードを整理できます。でも、Generics(ジェネリクス)を含むProtocol、つまりProtocol with Associated Type(PAT)はそのままでは使いにくいんです。その解決策がType Erasure(型消去)です。」
生徒
「型消去ってどういう意味ですか?」
先生
「難しく聞こえますが、ざっくり言えば“余計な型の情報を隠して、シンプルに扱えるようにする仕組み”です。たとえば、いろんな形のおもちゃを袋に入れて“おもちゃ”として扱うようなイメージですね。」
1. ProtocolとPATとは?
まずは基本から整理しましょう。SwiftのProtocolは「設計図」のようなものです。クラスや構造体に「この機能を必ず持ってね」と指示する仕組みです。
しかし、PAT(Protocol with Associated Type)と呼ばれるプロトコルは、型に依存する「関連型」を持っています。これは便利ですが、そのまま変数や配列にまとめて扱うことができません。
例えば、「データを入れ物にしまう」ようなプロトコルを考えてみます。
protocol Container {
associatedtype Item
func add(_ item: Item)
}
このようにassociatedtypeを使うと、「入れ物の中に入れる型」を後から自由に決められます。ただし、異なる型のContainerをひとまとめに管理するのは難しくなります。
2. なぜPATは使いにくいのか?
例えば、Containerを実装する構造体を2つ作ったとします。
struct IntBox: Container {
func add(_ item: Int) { print("Intを追加: \(item)") }
}
struct StringBox: Container {
func add(_ item: String) { print("Stringを追加: \(item)") }
}
ここで、両方のBoxを配列に入れてまとめて扱いたいと思っても、そのままではできません。理由は、Containerが「どんな型を扱うのか」が決まっていないからです。
つまり、PATは便利だけど「そのままでは配列や変数にできない」という欠点があるのです。
3. Type Erasure(型消去)の登場
ここで役に立つのがType Erasure(型消去)です。Type Erasureとは、具体的な型の情報を隠して、「とりあえずこのプロトコルを満たしているなら扱える」という形にする仕組みです。
身近な例で言えば、スーパーのレジ袋のようなものです。袋にリンゴやパンを入れても、外から見たら「袋」として同じように扱えます。
Swiftでは、この仕組みを作るために「ラッパー(包み紙)」となる構造体を作ります。
struct AnyContainer<T>: Container {
private let _add: (T) -> Void
init<C: Container>(_ container: C) where C.Item == T {
self._add = container.add
}
func add(_ item: T) {
_add(item)
}
}
このAnyContainerは「どんな具体的なContainerでも包み込んで同じように扱える」仕組みになっています。これがType Erasureです。
4. 実際にType Erasureを使ってみよう
では、さきほどのIntBoxとStringBoxをType Erasureでまとめてみましょう。
let intBox = IntBox()
let stringBox = StringBox()
let containers: [AnyContainer<Any>] = [
AnyContainer(intBox as! Container),
AnyContainer(stringBox as! Container)
]
// 共通の形式で扱える
containers.forEach { c in
c.add("テスト") // 文字列も追加可能
}
このようにType Erasureを使うことで、「型が違うけど同じように扱いたい」というニーズに応えられます。
5. Type Erasureが使われる場面
Type ErasureはSwift標準ライブラリでも使われています。例えばAnySequenceやAnyPublisherなどが代表例です。
これらは「中身がどんな型でも、とりあえずSequenceやPublisherとして扱える」ようにするための工夫です。初心者にとっては難しく見えますが、基本は「中身を隠して共通の顔にする」というシンプルな発想です。
日常の例えに置き換えると、「本、雑誌、漫画を全部まとめて“読み物”として本棚に並べる」と同じです。Type Erasureはまさにこの役割をSwiftの世界で担っています。
6. まとめると何が便利なのか?
初心者が最初に覚えておくべきポイントは以下です。
- Protocolは「設計図」
- PATは「型に依存する設計図」で便利だがそのままでは使いにくい
- Type Erasureは「型の違いを隠して共通の顔にする仕組み」
つまり、Type Erasureを理解すればSwiftのProtocolやExtensionをもっと自由に活用できるようになります。