Swift Academy · レッスン

anyと型消去による存在型

any Protocolを使い、パフォーマンスコストとジェネリックを優先すべき場面を学びます。

レッスン 3/413 ステップ

「anyと型消去による存在型」はCoddyKit上の無料Swift Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはSwift Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Swift Academyコースには全4レッスンが含まれています。

存在型とは

存在型は、プロトコルに準拠する任意の値を統一されたインターフェイスの背後にボックス化し、実行時に解決します。

protocol Drawable { func draw() }
struct Line: Drawable { func draw() { print("Line") } }
let d: any Drawable = Line()
d.draw()

any キーワード

Swift 5.7 では、存在型として使用するプロトコル名の前に any キーワードを付け、ボックス化を明示する必要があります。

func render(_ shape: any Drawable) {
  shape.draw()
}
render(Line())

存在型のコスト

存在型はヒープ割り当てと動的ディスパッチを使用するため、静的ディスパッチを使用するジェネリックより遅くなる場合があります。

// Existential – dynamic dispatch, potential heap alloc
var shapes: [any Drawable] = [Line(), Line()]
// Generic – static dispatch, no boxing
func drawGeneric<T: Drawable>(_ s: T) { s.draw() }

PAT と存在型の問題

関連型を持つプロトコル(PAT)は、型消去なしでは裸の存在型として使用できません。

protocol Container { associatedtype Item }
// var c: any Container // Swift 5.7 allows with "any" but loses Item info

型消去パターン

型消去ラッパーは、具体的な型をstructの背後にラップして、具体的な型を隠蔽します。

struct AnyDrawable: Drawable {
  private let _draw: () -> Void
  init<D: Drawable>(_ d: D) { _draw = d.draw }
  func draw() { _draw() }
}

AnySequenceとAnyPublisher

Swift標準ライブラリとCombineには、AnySequenceやAnyPublisherのような型消去ラッパーが用意されています。

import Combine
let subject = PassthroughSubject<Int, Never>()
let pub: AnyPublisher<Int, Never> = subject.eraseToAnyPublisher()

eraseToAnyPublisher()

eraseToAnyPublisher()は具体的なpublisherチェーンを隠蔽するため、呼び出し側はAnyPublisherだけに依存します。

func fetch() -> AnyPublisher<String, Error> {
  URLSession.shared.dataTaskPublisher(for: URL(string: "https://example.com")!)
    .map { String(data: $0.data, encoding: .utf8) ?? "" }
    .eraseToAnyPublisher()
}

存在型が適している場合

異種コレクションを扱う場合や、コンパイル時に正確な型がわからない場合は、存在型を使用してください。

var widgets: [any Drawable] = [] // mixed concrete types OK

存在型よりジェネリクスを優先する

可能であれば、存在型をジェネリクスに置き換えて、静的ディスパッチとパフォーマンスを得てください。

// Prefer this:
func draw<T: Drawable>(_ item: T) { item.draw() }
// Over this:
func draw(_ item: any Drawable) { item.draw() }

存在型を開く

Swift 5.7以降では、ジェネリック関数を呼び出す際に存在型を自動的に「開き」、基礎となる型を抽出できます。

func drawGeneric<T: Drawable>(_ d: T) { d.draw() }
let d: any Drawable = Line()
drawGeneric(d) // compiler opens the existential automatically

型消去と不透明型の違い

型消去は異種の型を扱うために型を隠蔽し、不透明型は単一の一貫した戻り値型として型の同一性を維持します。

let erased: any Drawable = Line()   // runtime type unknown
let opaque: some Drawable = Line()   // compile-time fixed type

理解度チェック

存在型で主に発生するパフォーマンスコストは何でしょうか。

レッスンのまとめ

存在型(any Protocol)を使うと、動的ディスパッチのコストと引き換えに実行時ポリモーフィズムを利用できます。型消去は、具体的な型を安定したインターフェースの背後にラップします。パフォーマンスを重視する場合はジェネリクスを優先し、異種コレクションには存在型を使用してください。

無料で開始

AI チューターと学ぶ Swift — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
122
レッスン
409

よくある質問

「anyと型消去による存在型」レッスンは無料ですか?

はい。「anyと型消去による存在型」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Swift Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Swift Academyコースには全4レッスンが含まれています。

「anyと型消去による存在型」で何を学びますか?

any Protocolを使い、パフォーマンスコストとジェネリックを優先すべき場面を学びます。 ブラウザで直接実行するハンズオンコードでSwift Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Swift Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのSwift Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「anyと型消去による存在型」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このSwift Academyレッスンでコードを書いて実行できますか?

はい。すべてのSwift Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. ジェネリック制約とwhere句
  2. someキーワードによる不透明型
  3. anyと型消去による存在型
  4. プライマリ関連型と型付きthrows
← Swift Academyに戻る