Type Constraints で説明されているように、ジェネリックな関数や型に関連する型パラメータに、型制約で要件を定義することができます。

また、関連型に要件を定義することが有益な場合もあります。これには、型パラメータリストの一部として where 節を定義します。関連型が特定のプロトコルに準拠することや、特定の型パラメータと関連型が同じであることを、where 節によって要求することができます。型パラメータのリストの直後に where キーワードを置き、関連型や型と関連型の相等関係に対する制約を続けて where 節を記述します。

下の例では、2 つの Container インスタンスに同じアイテムが同じ順序で含まれているかをチェックするジェネリック関数 allItemsMatch を定義しています。この関数は、すべてのアイテムが一致する場合に true のブール値を、そうでない場合には false の値を返します。

チェックされる 2 つのコンテナは同じ型のコンテナである必要は(あっても構わないですが)ありませんが、同じ型のアイテムを保持する必要があります。この要件は、型制約と where 節の組み合わせで表現されています。

func allItemsMatch<
    C1: Container, C2: Container
    where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
    (someContainer: C1, _ anotherContainer: C2) -> Bool {

    // 両コンテナに含まれるアイテム数が同じであることを確認
    if someContainer.count != anotherContainer.count {
        return false
    }

    // アイテムの各ペアが同等であることを確認
    for i in 0..<someContainer.count {
        if someContainer[i] != anotherContainer[i] {
            return false
        }
    }

    // すべてのアイテムが一致しているため true を返す
    return true

}

この関数は someContainer と anotherContainer の 2 つの引数を取ります。引数 someContainer は C1 型で、引数 anotherContainer は C2 型です。C1 と C2 は共に、関数が呼び出されたときに決まるコンテナ型の型パラメータです。

関数の型パラメータリストは、2 つの型パラメータに次の要件を要求しています。

  • C1 は Container プロトコルに準拠すること (C1: Container)
  • C2 は Container プロトコルに準拠すること (C2: Container)
  • C1 の ItemType は C2 の ItemType と同じであること (C1.ItemType == C2.ItemType)
  • C1 の ItemType は Equatable プロトコルに準拠すること (C1.ItemType: Equatable)

3 つ目と 4 つ目の要件は where 節の一部として定義されていて、関数の型パラメータリストの一部として where キーワードの後に記述されています。

これらの要件は、次のような意味になります。

  • someContainer は C1 型のコンテナである
  • anotherContainer は C2 型のコンテナである
  • someContainer と anotherContainer には同じ型のアイテムが含まれる
  • someContainer のアイテムが互いに異なっているかを確認するために !=(等しくない)演算子でチェックすることができる

3 つ目と 4 つ目の要件の組み合わせで、anotherContainer にあるアイテムについても、someContainer にあるアイテムとまったく同じ型であるため、!= 演算子でチェックできることを意味します。

これらの要件によって、2 つのコンテナが異なるコンテナ型であったとしても、allItemsMatch(_:_:) 関数で比較できるようになっています。

allItemsMatch(_:_:) 関数は、両コンテナに含まれるアイテム数が同じであることをはじめにチェックしています。アイテム数が異なる場合、一致することはありえず、関数は false を返します。

このチェック後、関数は forin ループと半開範囲演算子 (..<) で someContainer にあるすべてのアイテムを繰り返し処理します。各アイテムに対して、someContainer のアイテムとそれに対応する anotherContainer のアイテムが等しくないかどうかをチェックします。2 つのアイテムが等しくない場合には 2 つのコンテナは一致せず、関数は false を返します。

誤った組み合わせを見つけることなくループが終了した場合、2 つのコンテナは一致し、関数は true を返します。

次は、allItemsMatch(_:_:) 関数がどのように動作するかを示しています。

var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")

var arrayOfStrings = ["uno", "dos", "tres"]

if allItemsMatch(stackOfStrings, arrayOfStrings) {
    print("All items match.")
} else {
    print("Not all items match.")
}
// "All items match." と出力

この例は String 値を保管する Stack インスタンスを生成し、スタックに 3 つの文字列をプッシュしています。また、スタックと同じ 3 つの文字列を含む配列リテラルで初期化された Array インスタンスを生成しています。スタックと配列の型は異なりますが、共に Container プロトコルに準拠し、同じ型の値が含まれています。そのため、これらの 2 つのコンテナを引数として allItemsMatch(_:_:) 関数を呼び出すことができます。上の例では、allItemsMatch(_:_:) 関数が 2 つのコンテナにあるアイテムがすべて一致することを正しく報告しています。


Portions of this page are translations based on work created and shared by Apple and used according to terms described in the Creative Commons Attribution 4.0 International License.