0Pricing
Swift Academy · レッスン

条件付き適合

制約を満たす場合にのみ、ジェネリック型を適合させます。

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

条件付き適合とは

条件付き適合を使うと、型パラメーターが特定の制約を満たす場合に限り、ジェネリック型をプロトコルに適合させられます。典型的な例は、ElementがEquatableの場合に限り、ArrayがEquatableになることです。

extension Array where Element: Equatable {
    func allEqual(to x: Element) -> Bool {
        allSatisfy { $0 == x }
    }
}

組み込みの例

標準ライブラリでは、すでにこの仕組みが使われています。IntがEquatableなので、[Int]もEquatableです。2つの配列は、要素ごとに比較されます。

let a = [1, 2, 3]
let b = [1, 2, 3]
print(a == b)

条件付き適合の宣言

where句を使って、プロトコルへの適合を追加するextensionを記述します。ここでは、ラッパーが保持する値の型がEquatableの場合に限り、ラッパーをEquatableに適合させています。

struct Pair<T> {
    let first: T
    let second: T
}

extension Pair: Equatable where T: Equatable {
    static func == (l: Pair, r: Pair) -> Bool {
        l.first == r.first && l.second == r.second
    }
}

print(Pair(first: 1, second: 2) == Pair(first: 1, second: 2))

制約が重要な理由

制約がなければ、ラップされた値を比較するには値そのものが比較可能である必要があるため、コンパイラーは==を自動合成できません。where句が、その保証を正確に与えています。

struct Box<T> { let value: T }
extension Box: Equatable where T: Equatable {}

print(Box(value: "hi") == Box(value: "hi"))
print(Box(value: 5) == Box(value: 9))

条件付きの Codable

Codableにも条件付きで適合できます。コンテナーは、その要素がCodableの場合に限り、エンコード可能になります。

struct Wrapper<T> { let payload: T }
extension Wrapper: Codable where T: Codable {}

let w = Wrapper(payload: 42)
let data = try! JSONEncoder().encode(w)
print(String(data: data, encoding: .utf8)!)

複数の制約

where句には、コンマで区切って複数の要件を記述できます。

struct Stack<T> { var items: [T] = [] }

extension Stack where T: Comparable {
    func maxItem() -> T? { items.max() }
}

var s = Stack<Int>()
s.items = [3, 9, 1]
print(s.maxItem()!)

条件付きの CustomStringConvertible

内容が出力可能な場合に限り型を出力可能にし、要素から説明文を組み立てます。

struct Labeled<T> { let label: String; let value: T }

extension Labeled: CustomStringConvertible where T: CustomStringConvertible {
    var description: String { label + ": " + value.description }
}

print(Labeled(label: "Age", value: 30))

ネストした条件付き適合

条件付き適合は組み合わせられます。Intの配列の配列がEquatableになるのは、各階層で制約が連鎖するためです。

let grid1 = [[1, 2], [3, 4]]
let grid2 = [[1, 2], [3, 4]]
print(grid1 == grid2)

別のプロトコルへの制約

where句では、要素が自分で定義したプロトコルに適合することを要求できます。これにより、そのプロトコルに基づく機能を利用できます。

protocol Priced { var price: Double { get } }
struct Item: Priced { let price: Double }

extension Array where Element: Priced {
    var totalPrice: Double { reduce(0) { $0 + $1.price } }
}

print([Item(price: 1.5), Item(price: 2.5)].totalPrice)

同一型制約

==を使うと、関連型を特定の型に制約できます。ここでは、メソッドがStringの配列に対してのみ適用されます。

extension Array where Element == String {
    func joinedUpper() -> String {
        map { $0.uppercased() }.joined(separator: "-")
    }
}

print(["a", "b", "c"].joinedUpper())

コンパイラーによる活用方法

条件付き適合を使うと、コンパイラーはプロトコルの機能を、それが有効な場合に限って正確に付与できます。そのため、ジェネリックコードの安全性と再利用性を最大限に保てます。

struct Optional2<T> { let value: T? }
extension Optional2: Equatable where T: Equatable {
    static func == (l: Optional2, r: Optional2) -> Bool { l.value == r.value }
}
print(Optional2(value: 1) == Optional2(value: 1))

理解度チェック

条件付き適合についての理解度を確認しましょう。

まとめ

条件付き適合では、extension Type: Protocol where ...を使い、型パラメーターが制約を満たす場合に限って適合を付与します。Equatable、Codable、CustomStringConvertibleでの例に加え、プロトコル制約、同一型制約(==)、ネストについて確認しました。これにより、ジェネリック型の安全性と再利用性を保てます。

よくある質問

「条件付き適合」レッスンは無料ですか?

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

「条件付き適合」で何を学びますか?

制約を満たす場合にのみ、ジェネリック型を適合させます。 ブラウザで直接実行するハンズオンコードでSwift Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

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

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

「条件付き適合」レッスンにはどのくらい時間がかかりますか?

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

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

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

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

  1. 契約としてのプロトコル
  2. エクステンションでのデフォルト実装
  3. プロトコル合成
  4. 条件付き適合
← Swift Academyに戻る