Opaque Type: Swiftにおけるsomeとanyとは

著者: IT Sectr 公開日: 2026-06-18 読了時間: 11 分

Opaque Type(不透明な型)は、関数がコール側に具体的な型を明かさずにある型の値を戻すことを許すSwiftのメカニズムです。戻り値の型におけるsomeキーワードは最も有名な例です: SwiftUIでのsome Viewは「関数がViewに準拠するいくつかの型を戻すが、どの型かは実装詳細だ」という意味です。Opaque typeは型のアイデンティティを保持します(型としてのプロトコルとは異なり)。これにより、コンパイラがコードを最適化し、戻される型の一貫性を保証できます。Swift Book, 2025によると、opaque typesは関連型を持つプロトコルの問題を解決し、そのようなプロトコルの値を関数から戻すことを可能にします。

ポイント

  • Opaque Type — コール側から具体的な実装を隠す戻り値の型
  • some — 戻り値の位置でopaque typeを宣言するためのキーワード
  • 型のアイデンティティが保持される: コンパイラは具体的な型を知っており、anyとは異なる
  • SwiftUIはbodyを宣言する標準的な方法としてsome Viewを使用する
  • 制限: someを使う関数はすべてのブランチから同じ具体的な型を戻す必要がある

SwiftにおけるOpaque Typeとは?

Opaque Typesomeキーワードで宣言される戻り値の型で、コール側から具体的な実装を隠します。コール側は、戻された値が特定のプロトコルに準拠していることしか知らず、someの背後にどの型があるのかは知りません。その間、コンパイラは正確な型を知っており、静的ディスパッチと最適化に使用します。

Opaque Typeが解決する問題

Swift 5.1 (SE-0244)でopaque typesが導入される前は、ボックスラッパーなしで関数から関連型を持つプロトコルを戻すことが不可能でした。例えば、Equatableプロトコルには関連型があり、関数は単にEquatableを戻すことができませんでした — コンパイラは「プロトコルはジェネリック制約としてのみ使用できます」というエラーを出しました。Opaque typeがこの問題を解決しました。

swift
func makeInt() -> some Equatable {
    return 42
}

func makeString() -> some Equatable {
    return "Hello"
}

// コンパイラはmakeIntがIntを戻すことを知っている
// makeInt() == makeString() — ❌ エラー、異なる型

両方の関数はsome Equatableを戻しますが、具体的な型は異なります: IntとStringです。これらを==で比較しようとするとコンパイルエラーが発生します。なぜなら、opaque typeは特定の呼出しが同じ型を戻すことを保証しますが、異なる関数間では保証しないからです。これは機能であってバグではありません: opaque typeは、型としてのプロトコル(any Equatable)が失う型のアイデンティティを保持します。

Opaque Type vs Generic: 違いとは

GenericOpaque Typeは表裡一体です。ジェネリックはコール側が型を選択でき、opaque typeは関数がコール側から型を隠すことができます。違いは制御の方向にあります。

特徴Generic Opaque some
型を誰が選ぶかコール側のコード関数/メソッド
型のアイデンティティ保持される(安定)保持される(安定)
戻り値のブランチ数一つ(ジェネリックにより)すべてのブランチで同じ型
使用例アルゴリズム、データ構造SwiftUI、ファクトリメソッド

Generic — 外部からの選択

ジェネリック関数では、コーラーが使用する型を決定します。関数は制約を満たすどのようなTでも動作する必要があります。Opaque typeでは、コーラーは具体的な型を知らず、実装が決定します。

swift
// Generic: コーラーが型を選択する
func identity<T>(_ value: T) -> T { value }
let x: Int = identity(42)

// Opaque: 関数が型を隠す
func makeSomeEquatable() -> some Equatable { 42 }
let y = makeSomeEquatable()

ジェネリックとopaque typeの選択は意図によります。コール側が型を選ぶ必要があればジェネリックを使用します。関数が実装詳細を隠す必要があればsomeを使用します。SwiftUIがsome Viewを選んだのは、bodyが内部的に柔軟であるが外部的に安定する必要があったからです。

someキーワードとその使用法

someはSwift 5.1 (SE-0244)で導入されたSwiftのキーワードです。戻り値の位置でopaque typeを宣言するために使用され、またパラメータ(SE-0341)やプロパティでも使用できます。someは、具体的な型が安定しておりコンパイラに知られているが、外部のコードからは隠されていることを保証します。

関数パラメータでのsome

Swift 5.7から、someは戻り値の位置だけでなく、パラメータでも使用できます。パラメータでのsome Equatableは「この関数はどのようなEquatable型でも受け付けるが、特定のボディ内のすべての呼出しは同じ型を見る」という意味です。

swift
func areEqual(_ a: some Equatable, _ b: some Equatable) -> Bool {
    // aとb — 異なる可能性のある型、==は直接動作しない
    return isEqual(a, b)
}

func isEqual<T: Equatable>(_ a: T, _ b: T) -> Bool {
    return a == b
}

パラメータでsomeを使用すると、と比較してより簡潔な構文です。これは特にプロトコルとプロトコル向け設計において有用で、プロトコルの使用ごとに独立したジェネリックパラメータを必要としません。コンパイラはsomeパラメータを内部的にジェネリックに変換するため、パフォーマンスは同じです。

anyキーワードと存在的型

anyはSwift 5.6+のキーワードで、存在的型(型としてのプロトコル)を明示的に宣言するためのものです。someとは異なり、anyは型のアイデンティティを消します: コンパイラはプロトコルの背後にどの具体的な型が隠れているかを知りません。これは柔軟性(同じ配列に異なる型を格納できる)を提供しますが、パフォーマンスの代償です。

some vs any: 比較分析

some — 静的ポリモーフィズム: コンパイラは具体的な型を知り、直接ディスパッチを使用し、コードをインラインできます。any — 動的ポリモーフィズム: 仮想メソッドテーブル(存在的コンテナ)が使用され、間接性が増します。

swift
protocol Drawable {
    func draw()
}

// some: 静的な型が知られている
func makeDrawable() -> some Drawable {
    return Circle() // 単一の戻り値の型
}

// any: 動的、異なる型を格納できる
var shapes: [any Drawable] = [Circle(), Square()]
shapes.append(Triangle())

someとanyの選択はパフォーマンスと柔軟性のトレードオフです。Someはより高速ですが単一の実装に制限されます。Anyはより柔軟(型を混合できる)ですが、動的ディスパッチにより遅くなります。SwiftUIでは、bodyはいつもsome Viewを使用します。なぜなら、各Viewのbodyは単一の具体的な型だからです。

関連型を持つプロトコルでのOpaque Type

Opaque TypeはSwiftの根本的な問題を解決します: 関連型を持つプロトコル(PAT)は型として直接使用できません。関数は単にCollectionを戻すことができません — コンパイラはElementを指定するよう求めます。some Collectionは関連型を隠すことでこれを解決します。

PATをsomeを通じて戻す

Opaque typeなしでは、Collectionを戻すには具体的な型(Array)または型イレージ(AnyCollection)を使用する必要がありました。some Collectionは中間の立場を提供します: コンパイラは具体的な実装を知っており、コール側のコードは知りません。

swift
func makeReversedCollection<T>(
    of array: [T]
) -> some Collection {
    return array.reversed()
}

let result = makeReversedCollection(of: [1, 2, 3])
// result — ReversedCollection>, hidden from caller
for item in result {
    print(item)
}

resultは反復可能ですが、ReversedCollectionのプロパティに直接アクセスすることはできません。これはエンキャプセレーションを保護します: 後でreversed()を異なる実装の別のメソッドに置き換えても、コール側のコードは壊れません。Opaque typeはAPIを変えずに実装を変更する自由を与えます。

SwiftUIにおけるsome Viewの実践例

some Viewはopaque typeの最も有名な使用例です。SwiftUIの各Viewはbodyをsome Viewとして宣言します。これは、bodyがいくつかの具体的なViewの型を戻すことを意味しますが、開発者は実際にどの型かを考える必要がありません — TupleView、Group、ModifiedContent、またはフレームワークの他の型です。

SwiftUIがどのようにsome Viewを使用するか

Opaque typeなしでは、bodyは具体的な型を戻す必要があります。例えばModifiedContent<Button<Text>, Padding>などで、現実的ではありません。some Viewはこの複雑さを隠します。コンパイラはコンパイル時にbodyの正確な型を自動的に推論します。

swift
struct ContentView: View {
    var body: some View {
        VStack {
            Text("こんにちは")
                .font(.title)
            Button("タップしてください") {
                print("タップされました")
            }
        }
        .padding()
    }
}

コンパイラはbodyをModifiedContent<VStack<TupleView<(Text, Button<Text>)>>, Padding>として推論します。開発者はsome Viewを見ます。レイアウトをVStackからHStackに変更すると、コンパイラは自動的に型を再推論します — 手動での編集は不要です。これがopaque typeの魔法です: 開発者はインタフェースのロジックに集中し、構成タイプには集中しません。

よくある質問

SwiftにおけるOpaque Typeとは?

Opaque Typeはsomeキーワードで宣言される型で、コール側から具体的な実装を隠します。コンパイラは正確な型を知っていますが、関数を使用する開発者はプロトコルしか見えません。

Swiftでsomeとanyはどう違いますか?

someは静的なアイデンティティを持つopaque typeです: コンパイラは具体的な型を知っています。anyは動的ディスパッチを持つ存在的型です: 型のアイデンティティは消されます。Someは効率的で、anyは柔軟です。

なぜSwiftUIはsome Viewを使用するのですか?

some Viewは、コンパイラが自動的に推論するbodyの複雑な具体的な型を隠します。これにより開発者は、ジェネリックなラッパー(VStack、Group、ModifiedContent)からなる正確な型を書く必要がありません。

関数パラメータでsomeを使用できますか?

はい、Swift 5.7から可能です。パラメータでのsomeはジェネリックパラメータの構文糖です。関数宣言を簡素化し、特に各someパラメータが独立したを必要としないプロトコルでの作業に有用です。

some関数から異なる型を戻すとどうなりますか?

コンパイラはエラーを出します: opaque typeはすべての戻り値のブランチが同じ具体的な型を戻すことを必要とします。これは型のアイデンティティを保持するための意図的な設計です。異なる型を戻す必要があれば、anyを使用してください。

まとめ

  • Opaque Type — コンパイラレベルでアイデンティティを保持しつつ戻り値の具体的な型を隠す
  • someキーワードは戻り値の位置とパラメータでopaque typeを宣言するために使用される
  • Generic vs Opaque: コーラーがジェネリックの型を選び、実装がopaqueの型を選ぶ
  • any — 動的ディスパッチを持つ存在的型、some — 静的ポリモーフィズム
  • SwiftUI some View — 主な使用例: 開発者からbodyの複雑な型を隠す
  • Opaque typeは関数から関連型を持つプロトコル(PAT)を戻す問題を解決する

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください