0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Swift ジェネリクスまとめ

Posted at

Swift ジェネリクスまとめ

✅ ジェネリクスの理解に必要な基本要素

  • ジェネリクス(Generics)とは何か:型を抽象化して、型に依存しない再利用可能なコードを書く仕組み。
  • 基本構文func <T>(_ value: T) {}struct Wrapper<T> {} など。
  • 標準ライブラリでの使用例Array<T>Optional<T> は典型的なジェネリクスの活用例。

✅ 実務で求められる応用理解

  • 型制約(型パラメータの制限)<T: Equatable>where T: Hashable などを使い、安全に型を扱う。
  • プロトコルとの組み合わせfunc load<T: Decodable>() -> T のように、型制約付きでデコード処理を抽象化できる。
  • 型消去(type erasure)との関係AnyPublisher, AnyView などは型消去によって異なる型を統一。

✅ associatedtype と some / any の使い分け

Swiftでは、associatedtype を含むプロトコルはそのまま型として使うことができません。なぜなら、associatedtype はプロトコル準拠時に具体型が決定されるもので、プロトコル自体にはその型情報が含まれていないためです。つまり「どの型を使うか分からないので、安全に操作できない」ということです。

🔹 associatedtypeとは?

associatedtype は「ジェネリクスで扱う型に名前をつける」ものです。プロトコルにおける「型引数」のような役割で、準拠先によって型が決まる柔軟性を持ちます。

protocol Container {
    associatedtype Item
    func add(_ item: Item)
    var items: [Item] { get }
}

この制約を克服し、柔軟に型を扱うための方法が someany です。

  • some:ある1つの具体的な型を返すことを意味する構文。ジェネリクス的な扱いができる。
func makeContainer() -> some Container {
    return IntContainer()
}

→ 呼び出し側ではその中身(型)が保持されているため、型安全に操作可能です。

  • any:プロトコル型を明示的に使う構文(Swift 5.7〜)。型の詳細は捨てる(型消去)。
let container: any Container = IntContainer()

Item の型情報が失われるため、型依存の操作(addやitemsアクセス)はできなくなります。

このように、someany は「associatedtype を含むプロトコルをどう扱うか」という目的のために用意された手段です。


✅ 利用側のコードの違い(some vs any)

🔹 some を使った場合(型が分かる)

var container = makeContainer() // some Container(実体は IntContainer)
container.add(1) // ✅ OK
print(container.items.first) // ✅ OK

🔸 any を使った場合(型が消える)

let container: any Container = IntContainer()
container.add(1) // ❌ エラー
let first = container.items.first // ❌ エラー

→ 解決するには型消去ラッパー(例:AnyContainer<Int>)が必要。

AnyContainer<T> を使った解決例

struct AnyContainer<T>: Container {
    private var itemsStorage: [T] = []
    var items: [T] { itemsStorage }
    mutating func add(_ item: T) {
        itemsStorage.append(item)
    }
}

var container = AnyContainer<Int>()
container.add(1)
container.add(2)
print(container.items) // ✅ [1, 2]

✅ 型安全性とは?

  • 型安全性:プログラムが「型に関して正しく記述されている」状態。
  • Swiftは型安全な言語であり、型に合わない操作はコンパイル時にエラーになる。
  • 型安全な設計は、バグの発生を未然に防ぎ、保守性と信頼性を高める。

🔸 型安全でない言語の例(JavaScript)

let name = "Taro";
let age = 20;
let result = name + age; // "Taro20"(意図しない挙動)

✅ 型安全な設計(Swift)

let name: String = "Taro"
let age: Int = 20
// let result = name + age // ❌ コンパイルエラー

❌ 型安全でない設計(SwiftのAny)

func printValue(_ value: Any) {
    if let intVal = value as? Int {
        print(intVal + 1)
    } else {
        print("Unknown type")
    }
}

printValue("Hello") // 実行時に型を判断 → 不安全

✅ 比較表

観点 型安全なコード 型安全でないコード
エラー発見 コンパイル時 実行時(遅い)
バグ発生率 低い 高い
IDE補完 利用できる 使いにくい
型変換 明示的 暗黙または手動でキャスト

✅ ジェネリクスと型消去の違い

観点 ジェネリクス 型消去(type erasure)
型の決定 コンパイル時に決定 ランタイムで抽象化
型情報 保持される 消される(アクセス不可)
性能 高い(最適化されやすい) やや落ちる(動的ディスパッチ)
柔軟性 高い(型ごとの処理が可能) 高い(異種型を統一して扱える)

✅ AnyView と any View の違い

  • ``:SwiftUIが提供する型消去用の構造体。異なるView型(例:TextとImage)をまとめるために使う。
func makeView() -> AnyView {
    if flag { return AnyView(Text("A")) }
    else { return AnyView(Image(systemName: "star")) }
}
  • ``:Swift 5.7以降で導入された、プロトコル型(View)を明示的に使う構文。型消去のための構文糖。
let view: any View = Text("Hello")
  • 両者は似ているが、AnyView は SwiftUI専用、any View はSwift言語全体の型消去構文という違いがある。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?