ジェネリック(汎用)


汎用(Generic)コード を使用すると、定義する要件の対象と全ての型を扱うことができ、柔軟で再利用可能な関数と型を書くことができます。重複を避け、明確な、抽象化の方法でその意図を表現するコードを書くことができます。


ジェネリック (汎用)は、Swift の最も強力な機能の一つであり、そして Swift の標準ライブラリの多くは汎用(ジェネリック)コードでビルドされています。実際に、それを意識していない場合でも、言語ガイド 全体を通して汎用を使用してきました。たとえば、Swift の ArrayDictionary 型は、両方とも汎用のコレクションです。Int 値を保持する配列、または String 値を保有する配列、または実際に Swift では他の全ての型用の配列を作成できます。同様に、指定した全ての型の値を格納するための dictionary を作成でき、その型が何であろうと制限はありません。


汎用が解決する問題


ここで 2つの Int 値を入れ替える、swapTwoInts(_:_:) と言う汎用でない関数を挙げます。


  1. func swapTwoInts(_ a: inout Int, _ b: inout Int) {
  2.         let temporaryA = a
  3.         a = b
  4.         b = temporaryA
  5. }


この関数は、In-Out パラメータ で説明したように、ab の値を交換するのに in-out パラメータを使用しています。


swapTwoInts(_:_:) 関数は、b の元の値を、a と入れ替え、 a の元の値を b と入れ替えます。2つの Int 変数の値を交換するために、この関数を呼び出せます。


  1. var someInt = 3
  2. var anotherInt = 107
  3. swapTwoInts(&someInt, &anotherInt)
  4. print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
  5. // prints "someInt is now 107, and anotherInt is now 3"


swapTwoInts(_:_:) 関数は有用ですが、それは Int 値でしか使用できません。2つの String 値、または2つの Double 値を交換したい場合は、以下に示す様に、swapTwoStrings(_:_:)swapTwoDoubles(_:_:) 関数など多くの関数を書かなければなりません:


  1. func swapTwoStrings(_ a: inout String, _ b: inout String) {
  2.         let temporaryA = a
  3.         a = b
  4.         b = temporaryA
  5. }
  6. func swapTwoDoubles(_ a: inout Double, _ b: inout Double) {
  7.         let temporaryA = a
  8.         a = b
  9.         b = temporaryA
  10. }


swapTwoInts(_:_:)、swapTwoStrings(_:_:)、および swapTwoDoubles(_:_:) 関数の本体が同一であることに気づいたかもしれません。唯一の違いは、それらが受け入れる値 (Int、String、および Double) の型だけです。


全て の型の2つの値を交換できる一つの関数を書くようにできれば、はるかに有用で、著しく柔軟になります。汎用コードを使用すると、そのような関数を書くことができます。(これらの関数の汎用バージョンは後で定義します。)


注意: これら3つのすべての関数で、ab の型が同じでなければなりません。ab が同じ型ではなかった場合には、それらの値を交換することは不可能です。Swift は、タイプセーフな言語であり、(例えば) String 型の変数と Double 型の変数を互いに値を交換するのは許可されていません。これを実行しようとすると、コンパイル時エラーになります。


汎用関数


汎用関数 は、全ての型を扱うことができます。ここで上に挙げた swapTwoInts(_:_:) 関数の汎用バージョンで、swapTwoValues(_:_:) と言う例を挙げます:


  1. func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
  2.         let temporaryA = a
  3.         a = b
  4.         b = temporaryA
  5. }


swapTwoValues(_:_:) 関数の本体は swapTwoInts(_:_:) 関数の本体と同一です。しかし、swapTwoValues(_:_:) の最初の行は swapTwoInts(_:_:) とは少し異なります。ここで最初の行を比較してみましょう。


  1. func swapTwoInts(_ a: inout Int, _ b: inout Int)
  2. func swapTwoValues<T>(_ a: inout T, _ b: inout T) {

関数の汎用 (ジェネリック) バージョンは、(この場合は、T と言う) プレースホルダー 型の名を、実際の 型の名 (Int、String、または Double など) の代わりに使用しています。プレースホルダー型の名は、T でなければならないとは言っていませんが、ab の両方が T が表すのが何であれ、同じ型 T でなければならないと 告げ ています。T の代わりに使われる実際の型は swapTwoValues(_:_:) 関数が呼び出されるたびに決定されます。


他の違いは、汎用関数の名前 (swapTwoValues(_:_:)) が山括弧 (<T>) 内にプレースホルダー型の名 (T) が続いているということです。括弧は TswapTwoValues(_:_:) 関数定義内のプレースホルダー型の名だと Swift に教えています。T はプレースホルダーであるため、Swift は T と言う実際の型は検索しません。


これらの値の両者が互いに同じ型のものであれば、全て の型の2つの値を渡すことができることを除いて、swapTwoValues(_:_:) 関数は、swapTwoInts と同じ方法で呼び出すことができます。 swapTwoValues(_:_:) が呼び出されるたびに、T に使用する型は、関数に渡された値の型から推測されます。


以下の2つの例では、T は、それぞれ IntString であることが推測されます。


  1. var someInt = 3
  2. var anotherInt = 107
  3. swapTwoValues(&someInt, &anotherInt)
  4. // someInt is now 107, and anotherInt is now 3
  5. var someString = "hello"
  6. var anotherString = "world"
  7. swapTwoValues(&someString, &anotherString)
  8. // someString is now "world", and anotherString is now "hello"


注意: 上記で定義された swapTwoValues(_:_:) 関数は、Swift の標準ライブラリの一部であり、そしてあなたのアプリで自動的に利用可能となる swap と言う汎用関数に触発されています。独自のコードで swapTwoValues(_:_:) 関数の動作が必要な場合は、独自の実装を提供するよりも、Swift の既存の swap(_:_:) 関数を使用できます。



型パラメータ


上記の swapTwoValues(_:_:) の例では、プレースホルダの型 T は、型パラメータ の例です。型パラメータは、プレースホルダ型を指定し、名前を付け、一致する山括弧の対の間に、関数名の直後に書かれています(<T> のように)。


型パラメータを指定するやいなや、関数のパラメータの型を定義するために使用でき(例えば swapTwoValues(_:_:) 関数の ab のパラメータのように)、また関数の戻り値の型として、また関数の本体内の型注釈として使用できます。それぞれの場合、型パラメータは関数が呼び出されるたびに 実際の 型に置き換えられます。(上記の swapTwoValues(_:_:) の例では、T は、関数が呼び出された最初の時は Int 型で置き換えられ、呼び出された二度目には String に置き換えられます。)


カンマで区切り、山括弧内で複数の型パラメータ名を書くことによって、1つ以上の型パラメータを提供できます。



型パラメータの命名


ほとんどの場合、型パラメータおよびジェネリック型またはそれが中で使用されていまる関数との関係について、読者に伝える Dictionary<key, Value> での KeyValueArray<Element> での Element などの説明的な名前を型パラメータは持っています。しかし、それらの間の有意義な関係がない場合、それは上記の swapTwoValues(_:_:) 関数内の T のような、 TUV のような単一の文字を使用して、それらに名前を付けるのが、従来のやり方です。


注意: 常にそれらが のプレースホルダであり、値のものではないことを示すために、(例えば、TMyTypeParameter のように) upper camel case の名前を型パラメータに与えて下さい。


汎用の型


汎用の関数に加えて、Swift は、独自の 汎用の型 を定義できます。これらは、ArrayDictionary と同様に、全て の型を扱うことができる、カスタムクラス、構造体、および列挙型です。


このセクションでは、Stack と言う汎用のコレクション型を書く方法を説明します。スタックは、配列に似た値の順序集合ですが、Swift の Array 型より操作の制限が厳密に設定されています。配列は新しい項目が挿入でき、配列内の任意の場所から除去できます。スタックは、しかし、新しい項目はコレクションの最後にのみ追加することができ(スタック上に新たな値を プッシュする として知られてい) ます。同様に、スタックは、項目をコレクションの末尾からのみ削除する(スタックから値を ポップする として知られています)ことができます。



注意: スタックの概念は、そのナビゲーション階層における View Controller をモデル化する UINavigationController クラスによって使用されています。 UINavigationController クラスの pushViewController(_:animated:) メソッドを呼び出してナビゲーションスタックにビューコントローラーを追加(またはプッシュ) するのに使い、 popViewControllerAnimated(_:) メソッドを呼び出してナビゲーションスタックからビューコントローラーを削除(または ポップ) します。コレクションを管理するためのアプローチとして厳しい "ラストイン、ファーストアウト" が必要なときにはいつでも、スタックは便利なコレクションモデルです。


下のイラストは、スタックのプッシュ/ポップ動作を示しています。



stackPushPop_2x


  1. スタック上には現在3つの値があります。
  2. 4番目の値が、スタックの最上部へ"プッシュ" されます。
  3. スタックは最上部に最新のものを乗せ、現在4つの値を保持します。
  4. スタック内の最上部の項目がポップ"されます。
  5. 値をポップした後、スタックは再び3つの値を保持します。

ここで Int 値のスタックのために、スタックの汎用でないバージョンを書く方法は以下のとおりです。


  1. struct IntStack {
  2.         var items = [Int]()
  3.         mutating func push(_ item: Int) {
  4.                 items.append(item)
  5.         }
  6.         mutating func pop() -> Int {
  7.                 return items.removeLast()
  8.         }
  9. }


この構造体は、スタック内に値を格納する items と言う Array プロパティを使用しています。Stack はスタックの上にプッシュする push と スタックからポップする pop の2つのメソッドを提供します。これらのメソッドは構造体の items 配列を変更(または 変異)する必要があるため、mutating としてマークされています。


上に示した IntStack 型は、Int 型の値のみで使用できます。値の 全ての 型のスタックを管理することができる 汎用の Stack クラスを定義することは、はるかに有用でしょう。


ここで、同じコードの汎用バージョンを挙げます:


  1. struct Stack<Element> {
  2.         var items = [Element]()
  3.         mutating func push(_ item: Element) {
  4.                 items.append(item)
  5.         }
  6.         mutating func pop() -> Element {
  7.                 return items.removeLast()
  8.         }
  9. }


Stack の汎用バージョンは本質的に汎用でないバージョンと同じであることに注目しましょう、しかし、Int の実際の型の代わりに、Element と言う型パラメータがあります。この型パラメータは、構造体の名前の直後に山括弧(<Element>) のペアの中に書かれています。


Element は、後に提供される型のプレースホルダ名を定義しています。この将来の型は構造体の定義内のどこでも "Element" で参照できます。この場合は、Element は3つの場所でプレースホルダとして使用されています。


それは汎用型であるため、Stack は、ArrayDictionary と同様な方法で、Swift で有効な 全て の型のスタックを作成できます。


山括弧の中のスタックに格納する型を書くことによって、新しい Stack インスタンスを作成して下さい。たとえば、文字列の新しいスタックを作成するには、Stack<String>() と書いて下さい。


  1. var stackOfStrings = Stack<String>()
  2. stackOfStrings.push("uno")
  3. stackOfStrings.push("dos")
  4. stackOfStrings.push("tres")
  5. stackOfStrings.push("cuatro")
  6. // the stack now contains 4 strings


ここで stackOfStrings がスタック上にこれらの4つの値をプッシュした後どのように見えるかを示します:



stackPushedFourStrings_2x


スタックから値をポップし、一番上の値、"cuatro" を削除し、戻ります。


  1. let fromTheTop = stackOfStrings.pop()
  2. // fromTheTop is equal to "cuatro", and the stack now contains 3 strings


ここで、スタックがその一番上の値をポップした後にどのように見えるかを示します:



stackPoppedOneString_2x


汎用型の拡張


汎用型を拡張するときは、拡張機能の定義の一部として型パラメータリストを提供しないで下さい。代わりに、元の 型の定義から型パラメータリストが拡張機能の本体内で利用可能であり、元の型パラメータの名前は、元の定義から型パラメータを参照するために使用されます。


以下の例では、スタックからポップすることなく、スタック上の一番上の項目を返す、topItem と言う読み取り専用の計算されたプロパティを追加するために、汎用の Stack 型を拡張します。


  1. extension Stack {
  2.         var topItem: Element? {
  3.                 return items.isEmpty ? nil : items[items.count - 1]
  4.         }
  5. }


topItem プロパティは型 Element の optional の値を返します。スタックが空の場合、topItemnil を返します。スタックが空でない場合、topItemitems 配列内の最後の項目を返します。


この拡張機能は型パラメータリストを定義していないことに注意してください。代わりに、Stack 型の既存の型パラメータ名、Element は、topItem の計算されたプロパティの optional の型を示すために拡張機能内で使用されています。


topItem の計算されたプロパティは、Stack インスタンスで使用できるようになり、それを削除する事なく、その先頭の項目にアクセスし、照会できるようになります。


  1. if let topItem = stackOfStrings.topItem {
  2.         print("The top item on the stack is \(topItem).")
  3. }
  4. // prints "The top item on the stack is tres."


型制約


swapTwoValues(_:_:) 関数と Stack 型は全ての型を扱うことができます。しかし、汎用関数と汎用型で使用できる型に特定の 型制約 を強制すると便利な場合があります。型制約は、型パラメータが、特定のクラスから継承しなければならず、特定のプロトコルまたはプロトコル構成に準拠することを指定します。


たとえば、Swift の Dictionary 型には辞書のキーとして使用できる型の制約があります。Dictionary に記載されているように、辞書のキーの型は ハッシュ可能 でなければなりません。つまり、それ自体を独自に表現可能にする方法を提供しなければなりません。Dictionary は、それが既に特定のキーの値を含んでいるかどうか確認できるようにそのキーがハッシュ可能である事を必要としています。この要件がなければ、 Dictionary は、特定のキーの値を挿入または置き換える必要があるかどうかを見分けることができませんし、またそれが辞書に既にある与えられたキーの値を見つけることもできないでしょう。


この要件は、Dictionary のキー型の、型制約により強制され、Swift 標準ライブラリで定義された特別なプロトコルの Hashable プロトコルに、そのキー型が準拠するべき事を指定します。 (String、Int、Double、および bool のような) Swift の基本的なすべての型は、デフォルトでハッシュ可能です。


カスタムの汎用型を作成する時、独自の型制約を定義することができ、そしてこれらの制約は、汎用プログラミングに多くの力を提供します。Hashable のような抽象的な概念は、それらの具象的な型よりも、それらの概念的な特性の点で型を特徴づけます。


型制約の構文


型パラメータリストの一部として、コロンで区切って、型パラメータの名前の後に、一つのクラスまたはプロトコル制約を配置することにより、型制約を書く事ができます。(構文は汎用型と同じですが) 汎用関数での型制約の基本的な構文を以下に示します。


  1. func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
  2.         // function body goes here
  3. }


上記の仮想の関数には、2つの型パラメータがあります。最初の型パラメータ T には、SomeClass のサブクラスである T を必要とする型制約があります。第二の型パラメータ、U には、プロトコル SomeProtocol に準拠するよう U に求める型制約があります。



実際の型制約


ここで検索する String 値と、それをその中で見つけるべき String 値の配列を、与えられている findIndex(ofString:in:) と言う汎用でない関数を示します。findIndex(ofString:in:) 関数は、それが見つかった配列内で最初に一致した文字列のインデックスの optional の Int 値を返し、または文字列が見つからない場合は nil を返します:


  1. func findIndex(ofString valueToFind: String, in array: [String]) -> Int? {
  2.         for (index, value) in array.enumerated() {
  3.                 if value == valueToFind {
  4.                         return index
  5.                 }
  6.         }
  7.         return nil
  8. }


findIndex(ofString:in:) 関数は、文字列の配列内の文字列値を見つけるために使用できます。


  1. let strings = ["cat", "dog", "llama", "parakeet", "terrapin"]
  2. if let foundIndex = findIndex(ofString: "llama", in: strings) {
  3.         print("The index of llama is \(foundIndex)")
  4. }
  5. // prints "The index of llama is 2"


配列内の値のインデックスを見つける原理は、しかし、文字列のみのためだけに有用ではありません。代わりに何らかの型 T の値を使用して文字列の全ての言及を置き換えて汎用関数として、同じ機能を書くことができます。


ここで、findIndex(of:in:) と言う findIndex(ofString:on:) の汎用版を書けることを期待している方法を記します。この関数の戻り値の型は、配列からの optional の値ではなく、optional のインデックス番号を返すため、まだ Int? であることに注意してください。しかし、注意して下さい、理由は例の後に説明しますが、この関数はコンパイルされません。:


  1. func findIndex<T>(of valueToFind :T, in array: [T]) -> Int? {
  2.         for (index, value) in array.enumerated() {
  3.                 if value == valueToFind {
  4.                         return index
  5.                 }
  6.         }
  7.         return nil
  8. }


上述したように、この関数は、コンパイルされません。問題は、"if value == valueToFind" の等価性チェックの所です。Swift のすべての型が、等価演算子 (==) で比較できるわけではありません。たとえば、複雑なデータモデルを表現するために、独自のクラスまたは構造体を作成した場合、その後そのクラスまたは構造体の"等しい" 意味が Swift に推測できるわけではありません。このため、このコードは、すべての 可能な型 T で動作することを保証できず、コードをコンパイルしようとすると、適切なエラーが報告されます。


すべては、しかし、失われません。Swift 標準ライブラリは、Equatable と言うプロトコルを定義し、その型のいずれかの2つの値を比較するために等価演算子 (==) と非等価演算子 (!=) を実装するように、全ての準拠型に要求します。Swift の標準的な型のすべてが自動的に Equatable プロトコルをサポートしています。


Equatable である全ての型は、findIndex(of:in:) 関数で安全に使用でき、というのもそれは等価演算子をサポートすることを保証しているためです。関数を定義するときに、この事実を表現するには、型パラメータの定義の一部として Equatable の型制約を書いて下さい。


  1. func findIndex<T: Equatable>(of valueToFind: T, in array: [T]) -> Int? {
  2.         for (index, value) in array.enumerated() {
  3.                 if value == valueToFind {
  4.                         return index
  5.                 }
  6.         }
  7.         return nil
  8. }


findIndex(of:in:) の一つの型パラメータは、T:Equatable と書かれ、これは "Equatable プロトコルに準拠する全ての型 T" を意味します。


findIndex(of:in:) 関数はうまくコンパイルするようになり、DoubleString のような Equatable である全ての型で使用できます:


  1. let doubleIndex = findIndex(of:9.3, in: [3.14159, 0.1, 0.25])
  2. // doubleIndex is an optional Int with no value, because 9.3 is not in the array
  3. let stringIndex = findIndex(of:"Andrea", in: ["Mike", "Malcolm", "Andrea"])
  4. // stringIndex is an optional Int containing a value of 2


関連型


プロトコルを定義する際には、プロトコルの定義の一部として 1 つ以上の関連型を宣言すると便利な場合があります。関連型 はプロトコルの一部として使用される型へのプレースホルダー名を与えます。関連型に使用する実際の型はプロトコルが採用されるまで、特定されません。関連型は associatedtype キーワードで指定されます。


実際の関連型


ここで Container と言うプロトコルの例をあげますが、これは Item と言う関連型を宣言します。


  1. protocol Container {
  2.        associatedtype Item
  3.        mutating func append(_ item: Item)
  4.        var count: Int { get }
  5.        subscript(i: Int) -> Item { get }
  6. }


Container プロトコルは、全てのコンテナが提供しなければならない3つの必要な機能を定義しています:


このプロトコルは、コンテナ内の項目がどのように格納されるべきか、それらがどのような型であるべきかを指定しません。プロトコルは、全ての型が Container と見なされるために提供しなければならない機能を3ビットだけ指定します。準拠型は、これら3つの要件を満たすように、追加の機能を提供できます。


Container プロトコルに準拠する全ての型は、格納する値の型を指定できなければなりません。具体的には、正しい型の項目だけがコンテナに追加されていることを確認しなければならず、そのサブスクリプトで返される項目の型が明確でなければなりません。


これらの要件を定義するには、Container プロトコルは、その型が特定のコンテナで何のためにあるのか知らずに、コンテナが保持する要素の型を参照するための方法が必要です。Containaer のプロトコルは、 append(_:) メソッドに渡された全ての値がコンテナの要素型と同じ型を持たなければならないと指定する必要があり、コンテナのサブスクリプトで返された値は、コンテナの要素型と同じ型のものになることを指定します。


これを実現するために、Container プロトコルは associatedtype Item として書かれた Item と言う関連型を宣言します。プロトコルは、Item が何かを定義しませんー提供する全ての準拠型のためにその情報は残されています。それにもかかわらず、Item エイリアスは、Container 内の項目の型を参照する方法を提供し、 append(_:) メソッドとサブスクリプトで使用するための型を定義し、全ての Container の期待される動作が守られているることを確認します。


ここで、以前の汎用でない IntStack 型を、Container プロトコルに準拠するように適合させたバージョンを示します。


  1. struct IntStack: Container {
  2.         // original IntStack implementation
  3.         var items = [Int]()
  4.         mutating func push(_ item: Int) {
  5.                 items.append(item)
  6.         }
  7.         mutating func pop() -> Int {
  8.                 return items.removeLast()
  9.         }
  10.         // conformance to the Container protocol
  11.         typealias Item = Int
  12.         mutating func append(_ item: Int) {
  13.                 self.push(item)
  14.         }
  15.         var count: Int {
  16.                 return items.count
  17.         }
  18.         subscript(i: Int) -> Int {
  19.                 return items[i]
  20.         }
  21. }


IntStack 型は、Container プロトコルの要件の3つ全てを実装し、それぞれの場合に、これらの要件を満たすために IntStack 型の既存の機能の一部を包み込みます。


また、IntStack は、Container のこの実装のために、使用する適切な ItemInt 型であることを指定します。 typealias Item = Int の定義は、Container プロトコルのこの実施のため、Item の抽象型を Int の具体的な型に変えます。


Swift の型推論のおかげで、実際には IntStack の定義の一部として Int の具体的な Item を宣言する必要はありません。IntStackContainer プロトコルの要件のすべてに準拠しているので、Swift は、単に append(_:) メソッドの item パラメータ型とサブスクリプトの戻り値の型を見ることで、使用する適切な Item を推測できます。実際、上記のコードから typealias Item = Int の行を削除した場合、Item のためどのような型を使用するべきか明らかであるため、すべては、まだ動作します。


また、汎用の Stack 型を Container プロトコルに準拠させることもできます。


  1. struct Stack<Element>: Container {
  2.         // original Stack<Element> implementation
  3.         var items = [Element]()
  4.         mutating func push(_ item: Element) {
  5.                 items.append(item)
  6.         }
  7.         mutating func pop() -> Element {
  8.                 return items.removeLast()
  9.         }
  10.         // conformance to the Container protocol
  11.         mutating func append(_ item: Element) {
  12.                 self.push(item)
  13.         }
  14.         var count: Int {
  15.                 return items.count
  16.         }
  17.         subscript(i: Int) -> Element {
  18.                 return items[i]
  19.         }
  20. }


今度は、型パラメータ Element は、append(_:) メソッドの item パラメータの型と、サブスクリプトの戻り値の型として使用されています。Swift は、したがって、その Element は、この特定のコンテナのため Item として使用するのは適切なタイプと推測できます。


既存の型を拡張して関連型を指定


拡張機能を持つプロトコル準拠の追加 で説明したように、プロトコルへの準拠を追加するために、既存の型を拡張できます。これは、関連型を持つプロトコルを含みます。


Swift の Array 型はすでに append(_:) メソッドを提供し、count プロパティ、およびその要素を取得するため Int インデックスとサブスクリプトを提供しています。これら三つの機能は、Container プロトコルの要件に合致しています。これは、単にその Array がプロトコルに適合する事を宣言して Container プロトコルに準拠するために、Array を拡張できることを意味します。拡張機能を持つプロトコルの採用を宣言 で説明したように、空の拡張機能でこれを行います:


extension Array: Container {}



配列の既存の append(_:) メソッドとサブスクリプトは、ちょうど上記の汎用 Stack 型と同様、Swift が Item で使用する適切な型を推論するのを可能にします。この拡張機能を定義すると、Container として全ての Araay を使用できます。



型注釈を使用して関連型を制約


型注釈をプロトコルの関連型に追加して、適合する型が型注釈で記述された制約を満たすことを要求することができます。たとえば、以下のコードでは、コンテナ内の項目を equatable にする必要がある Container のバージョンを定義しています。


  1. protocol Container {
  2.         associatedtype Item: Equatable
  3.         mutating func append(_ item: Item)
  4.         var count: Int { get }
  5.         subscript(i: Int) -> Item { get }
  6. }


Container のこのバージョンに適合するためには、コンテナの Item 型は Equatable プロトコルに準拠しなければなりません。


汎用のWhere 句


型制約 で説明したように、型制約は、汎用関数、サブスクリプトまたは型に関連付けられた型パラメータの要件を定義できます。


また、関連型の要件を定義することも有用です。汎用の where 句 を定義することによってこれを行って下さい。汎用の where 句は、関連型が特定のプロトコルに準拠していなければならないことを要求し、またはその特定の型パラメータと関連型が同じでなければならないことを要求します。汎用の where 句は、where キーワードで始まり、関連型と型の間の等価関係の制約が続きます。型や関数の本体の開き中括弧の直前に、汎用 where 句を書いて下さい。


以下の例では、2つの Container インスタンスが同じ順序で同じ項目を含んでいるかをチェックする、allItemsMatch と言う汎用関数を定義しています。関数は、すべての項目が一致する場合は true のブール値を返し、一致しない場合は false の値を返します。


チェックすべき二つのコンテナは、コンテナの同じ型である必要はないが (同じであってもよい)、同じ型の項目を保持しなければなりません。この要件は、型制約と汎用 where 句 の組み合わせによって表現されています。


  1. func allItemsMatch<C1: Container, C2: Container>
  2.         (_ someContainer: C1, _ anotherContainer: C2) -> Bool
  3.         where C1.Item == C2.Item, C1.Item: Equatable {
  4.                 // Check that both containers contain the same number of items.
  5.                 if someContainer.count != anotherContainer.count {
  6.                 return false
  7.                 }
  8.                 // Check each pair of items to see if they are equivalent.
  9.                 for i in 0..<someContainer.count {
  10.                         if someContainer[i] != anotherContainer[i] {
  11.                         return false
  12.                         }
  13.                 }
  14.                 // All items match, so return true.
  15.                 return true
  16. }


この関数は、someContaineranotherContainer と言う2つの引数を取ります。someContainer 引数は C1 型のものであり、anotherContainer 引数は C2 型のものです。C1C2 は両方とも、2つのコンテナの型パラメータで、関数が呼び出された際に決定されます。


関数の2つの型パラメータは、次の要件を配置しています:


第一および第二の要件は、関数の型パラメータリストに定義されており、第三および第四の要件は、関数の汎用 where 句で定義されています。


これらの要件は、以下を意味します:


第三及び第四の要件を合わせると、anotherContainer 内の項目 someContainer 内の項目と完全に同じ型であるため、!= 演算子で確認できることを意味します。


これらの要件は、それらが異なるコンテナ型であっても、二つのコンテナを比較する allItemsMatch(_:_:) 関数を可能にします。


allItemsMatch(_:_:) 関数は、両方のコンテナが同じ数の項目を含んでいることをチェックすることによって開始します。それらが異なる数の項目を含んでいる場合、それらが一致できる方法はなく、関数は false を返します。


このチェックを行った後、関数は for-in ループと半開放範囲演算子 (..<) で someContainer 内のすべての項目にわたって反復処理します。各項目について、関数は someContainer からの項目が anotherContainer の対応する項目と同じではないかチェックします。2つの項目が等しくない場合、2つのコンテナは、一致しておらず、関数は false を返します。


ループが不一致を見つけることなく終了した場合、二つのコンテナは一致し、関数は true を返します。


ここで、allItemsMatch(_:_:) 関数が実際にどのように見えるかを示します:


  1. var stackOfStrings = Stack<String>()
  2. stackOfStrings.push("uno")
  3. stackOfStrings.push("dos")
  4. stackOfStrings.push("tres")
  5. var arrayOfStrings = ["uno", "dos", "tres"]
  6. if allItemsMatch(stackOfStrings, arrayOfStrings) {
  7.         print("All items match.")
  8. } else {
  9.         print("Not all items match.")
  10. }
  11. // prints "All items match."


上記の例では、String 値を格納する Stack インスタンスを作成し、スタック上に3つの文字列をプッシュします。この例ではまた、スタックと同じ3つの文字列を含む配列リテラルで初期化された Array インスタンスも作成します。スタックと配列が異なる型のものであっても、それらの両方は、Container プロトコルに準拠しており、両者は同じ型の値を含みます。そのため、その引数としてこれら二つのコンテナで allItemsMatch(_:_:) 関数を呼び出すことができます。上記の例では、allItemsMatch(_:_:) 関数は二つのコンテナ内の項目がすべて一致していることを正しく報告します。


汎用の Where 句を含む拡張機能


また、汎用の where 句を拡張機能の一部として使用することもできます。以下の例では、以前の例の汎用の Stack 構造体を拡張して isTop(_:) メソッドを追加しています。


  1. extension Stack where Element: Equatable {
  2.         func isTop(_ item: Element) -> Bool {
  3.                 guard let topItem = items.last else {
  4.                         return false
  5.                 }
  6.                 return topItem == item
  7.         }
  8. }


この新しい isTop(_:) メソッドは、最初にスタックが空でないことを確認して、それから指定された項目をスタックの最上位の項目と比較します。isTop(_:) の実装では、== 演算子を使用しますが、Stack の定義には項目が equatable である必要はありません。そのため、汎用の where 句を使用せずにこれを実行しようとすると問題が発生します。そのため、== 演算子はコンパイル時エラーを起こします。汎用の where 句を使用すると、拡張機能に新しい要件を追加できるので、スタック内の項目が equatable である場合にのみ、isTop(_:) メソッドを追加します。


isTop(_:) メソッドの動作が実際にどうなるかは以下のとおりです。


  1. if stackOfStrings.isTop("tres") {
  2.         print("Top element is tres.")
  3. } else {
  4.         print("Top element is something else.")
  5. }
  6. // Prints "Top element is tres."


要素が equatable でないスタックで isTop(_:) メソッドを呼び出そうとすると、コンパイル時エラーが発生します。


  1. struct NotEquatable { }
  2. var notEquatableStack = Stack<NotEquatable>()
  3. let notEquatableValue = NotEquatable()
  4. notEquatableStack.push(notEquatableValue)
  5. notEquatableStack.isTop(notEquatableValue) // Error


汎用の where 句をプロトコルへの拡張機能とともに使用することができます。以下の例では、以前の例の Container プロトコルを拡張して startsWith(_:) メソッドを追加しています。


  1. extension Container where Item: Equatable {
  2.         func startsWith(_ item: Item) -> Bool {
  3.                 return count >= 1 && self[0] == item
  4.         }
  5. }


startsWith(_:) メソッドは、最初にコンテナに少なくとも 1 つの項目があることを確認し、コンテナ内の最初の項目が指定された項目と一致するかどうかをチェックします。この新しい startsWith(_:) メソッドは、コンテナの項目が equatable である限り、上記で使用されたスタックや配列を含め、Container プロトコルに準拠するすべての型で使用できます。


  1. if [9, 9, 9].startsWith(42) {
  2.         print("Starts with 42.")
  3. } else {
  4.         print("Starts with something else.")
  5. }
  6. // Prints "Starts with something else."


上記の例の汎用の where 句は、Item がプロトコルに準拠することを要求しますが、Item が特定の型である事を必要とする where 句を書くこともできます。例えば:


  1. extension Container where Item == Double {
  2.         func average() -> Double {
  3.                 var sum = 0.0
  4.                 for index in 0..<count {
  5.                         sum += self[index]
  6.                 }
  7.                 return sum / Double(count)
  8. }
  9. }
  10. print([1260.0, 1200.0, 98.6, 37.0].average())
  11. // Prints "648.9"


この例では、Item 型が Double のコンテナに average() メソッドを追加します。コンテナ内の項目を繰り返し処理して追加し、コンテナのカウントで除算して平均を計算します。浮動小数点除算を行う事ができるようになるために、Int から Double へカウントを明示的に変換します。


拡張機能の一部である汎用の where 句に複数の要件を含めることができ、これは、他の場所で記述する汎用の where 句と同様です。リストの各要件をコンマで区切ります。


関連する型と汎用の Where 句


関連する型に汎用の where 句を含めることができます。たとえば、Sequence プロトコルが標準ライブラリで使用するような反復する用語を含むバージョンの Container を作成するとします。これを書く方法は以下のとおりです。


  1. protocol Container {
  2.         associatedtype Item
  3.         mutating func append(_ item: Item)
  4.         var count: Int { get }
  5.         subscript(i: Int) -> Item { get }
  6.         associatedtype Iterator: IteratorProtocol where Iterator.Element == Item
  7.         func makeIterator() -> Iterator
  8. }


Iterator の汎用の where 句では、反復する用語の型にかかわらず、反復する用語はコンテナの項目と同じ項目型の要素を横断しなければなりません。makeIterator() 関数は、コンテナの反復する用語へのアクセスを提供します。


別のプロトコルから継承するプロトコルの場合、プロトコル宣言に汎用の where 句を含めることによって、継承された関連型に制約を追加して下さい。たとえば、以下のコードは、Item が Comparable に準拠していることを要求する ComparableContainer プロトコルを宣言しています。


protocol ComparableContainer: Container where Item: Comparable { }



汎用のサブスクリプト


サブスクリプトは汎用にでき、汎用の where 句を含めることができます。subscript の後ろで角括弧の中にプレースホルダ型の名前を書いて、サブスクリプトの本文の中括弧の直前に汎用の where 句を書いて下さい。例えば:


  1. extension Container {
  2.         subscript<Indices: Sequence>(indices: Indices) -> [Item]
  3.                 where Indices.Iterator.Element == Int {
  4.                         var result = [Item]()
  5.                         for index in indices {
  6.                                 result.append(self[index])
  7.                         }
  8.                         return result
  9.         }
  10. }


Container プロトコルへのこの拡張機能は、一連のインデックスを取り、与えられた各インデックスに項目を含む配列を返すサブスクリプトを追加します。この汎用のサブスクリプトは、以下のように制約されます。



まとめると、これらの制約は、indices パラメータに渡される値が整数のシーケンスであることを意味します。





前:プロトコル 次:自動参照カウント
目次
Xcode 9 の新機能

Swift:はじめに
Swift と Cocoa と Objective-C
Swift Blog より
Swift Blog より

  • ようこそ Swift へ(Part I)
  • Swift について
  • バージョン互換性
  • Swift のツアー
  • 単純な値
    制御フロー
    関数とクロージャ
    オブジェクトとクラス
    列挙型と構造体
    プロトコルと拡張機能
    エラー処理
    汎用(ジェネリック)
  • Swift 言語のガイド(Part II)
  • Swift の基本
  • 定数と変数
  • 定数と変数の宣言
    型注釈
    定数と変数の命名
    定数と変数の印刷
    コメント
    セミコロン
  • 整数
  • 整数の境界
    Int
    UInt
    浮動小数点数
    安全な型と型推論
    数値リテラル
  • 数値型変換
  • 整数変換
    整数と浮動小数点間の変換
    型エイリアス
    ブール型
    タプル
  • Optional
  • nil
    if 文と強制開封
    Optional の結合
    暗黙に開封された Optionals
    エラー処理
  • アサーション(断言)と前提条件
  • アサーションを使用したデバッグ
    前提条件の実施
  • 基本演算子
  • 専門用語
    代入演算子
  • 算術演算子
  • 剰余演算子
    単項マイナス演算子
    単項プラス演算子
    複合代入演算子
    比較演算子
    三項条件演算子
    Nil 合体演算子
  • 範囲演算子
  • 閉鎖範囲演算子
    半開放範囲演算子
    片方の範囲
  • 論理演算子
  • 論理 NOT 演算子
    論理 AND 演算子
    論理 OR 演算子
    論理演算子の組み合わせ
    明示的な括弧
  • 文字列と文字
  • 文字列リテラル
    複数行の文字列リテラル
    文字列リテラル内の特殊文字
    空の文字列の初期化
    文字列の可変性
    文字列は値の型
    文字を使った作業
    文字列と文字を連結
    文字列補間
  • ユニコード(Unicode)
  • Unicode スカラー
    文字列リテラルの中の特別の文字
    拡張書記クラスタ
    文字を数える
  • 文字列のアクセスと変更
  • 文字列のインデックス
    部分文字列
    挿入と削除
  • 文字列の比較
  • 文字列と文字の等価性
    接頭辞と接尾辞の等価性
  • 文字列の Unicode 表現
  • UTF-8 の表現
    UTF-16 表現
    Unicode のスカラー表現
  • コレクション型
  • コレクションの可変性
  • 配列
  • 配列型省略構文
    空の配列の作成
    デフォルト値を持つ配列の作成
    2つの配列を共にして一つの配列に
    配列リテラルでの配列の作成
    配列へのアクセスと変更
    配列の繰り返し処理
  • セット
  • セット型のハッシュ値
    セット型の構文
    空のセットの作成と初期化
    配列リテラルでセットの作成
    セットへのアクセスと変更
    セットを反復処理
  • セット操作の実行
  • 基本的なセットの操作
    セットの身分と等価性
  • Dictionary
  • Dictionary 型の省略型構文
    空の Dictionary を作成
    Dictionary リテラルで Dictionary の作成
    Dictionary のアクセスと変更
    Dictionary を繰り返し処理
  • フロー制御
  • For-In ループ
  • While ループ
  • While
    Repeat-While
  • 条件文
  • if 文
  • Switch
  • 暗黙の Fallthrough なし
    範囲の一致
    タプル(Tuples)
    値の結合
    Where
    複合した case
  • 制御転送文
  • Continue
  • Break
  • ループ文内の Break
    Switch 文内の Break
    Fallthrough
    ラベル付きの文
    早期終了
    API 利用可能性の確認
  • 関数
  • 関数の定義と呼び出し
  • 関数のパラメータと戻り値
  • パラメータなしの関数
    複数パラメータの関数
    戻り値なしの関数
    複数の戻り値を持つ関数
    optional のタプル型の戻り値
  • 関数引数のラベルとパラメータ名
  • 引数のラベルの指定
    引数ラベルの省略
    デフォルトのパラメータ値
    可変個引数のパラメータ
    In-Out パラメータ
  • 関数型
  • 関数型の使用
    パラメータ型としての関数型
    戻り値の型としての関数型
    入れ子になった関数
  • クロージャ
  • クロージャ式
  • ソートするメソッド
    クロージャ式の構文
    文脈から型を推論
    単一式クロージャからの暗黙的戻り値
    引数名の省略
    演算子メソッド
    後続クロージャ
    値のキャプチャ
    クロージャは参照型
    クロージャのエスケープ
    オートクロージャ
  • 列挙型
  • 列挙型の構文
    switch 文で列挙型の値の一致
    関連する値
  • 生の値
  • 暗黙に割り当てられた生の値
    生の値からの初期化
    再帰的な列挙型
  • クラスと構造体
  • クラスと構造体を比較
  • 定義の構文
    クラスと構造体のインスタンス
    プロパティにアクセス
    構造体型のためのメンバー化イニシャライザ
    構造体と列挙型は値型
  • クラスは参照型
  • ID 演算子
    ポインタ
    クラスと構造体の間の選択
    文字列、配列、辞書の代入とコピーの動作
  • プロパティ
  • 格納されたプロパティ
  • 定数構造体インスタンスの格納されたプロパティ
    遅延した格納されたプロパティ
    格納されたプロパティとインスタンス変数
  • 計算されたプロパティ
  • セッタ宣言の省略形
    読み取り専用の計算されたプロパティ
    プロパティ監視者
    グローバルとローカル変数
  • 型プロパティ
  • 型プロパティの構文
    型プロパティの照会と設定
  • メソッド
  • インスタンスメソッド
  • self プロパティ
    インスタンスメソッド内から値の型を変更
    変異メソッド内で self に代入
    型メソッド
  • サブスクリプト
  • サブスクリプトの構文
    サブスクリプトの使用法
    サブスクリプトのオプション
  • 継承
  • 基本クラスの定義
    サブクラス化
  • オーバーライド(上書き)
  • スーパークラスメソッド、プロパティ、サブスクリプトへのアクセス
    オーバーライドするメソッド
  • オーバーライドするプロパティ
  • プロパティのゲッタとセッタのオーバーライド
    プロパティ監視者のオーバーライド
    オーバーライドの防止
  • 初期化
  • 格納されたプロパティの初期値を設定
  • イニシャライザ
    デフォルトのプロパティ値
  • 初期化のカスタマイズ
  • 初期化パラメータ
    パラメータ名と引数ラベル
    引数ラベルのないイニシャライザのパラメータ
    Optional のプロパティ型
    初期化中に定数プロパティへの代入
  • デフォルトのイニシャライザ
  • 構造体型のためのメンバ化イニシャライザ
    値型のイニシャライザデリゲート
  • クラスの継承と初期化
  • 指定イニシャライザとコンビニエンスイニシャライザ
    指定とコンビニエンスイニシャライザの構文
    クラス型のイニシャライザデリゲート
    二相の初期化
    イニシャライザ継承とオーバーライド
    自動イニシャライザの継承
    実際の指定とコンビニエンスイニシャライザ
  • 失敗可能イニシャライザ
  • 生の値を持つ列挙型のための失敗可能イニシャライザ
    初期化失敗の伝播
    失敗可能イニシャライザのオーバーライド
    init! の失敗可能イニシャライザ
    必須イニシャライザ
    クロージャや関数でのデフォルトのプロパティ値設定
  • デイニシャライザ
  • デイニシャライザはどのように働くか
    作動中のデイニシャライザ
  • Optional の連鎖
  • 強制開封の代替としての Optional の連鎖
    Optional の連鎖のモデルクラスの定義
    Optional の連鎖を使用したプロパティへのアクセス
    Optional の連鎖を通じてメソッドを呼び出す
  • Optional の連鎖を通じてサブスクリプトへのアクセス
  • Optional 型のサブスクリプトにアクセス
    連鎖の複数レベルのリンク
    optional の戻り値を持つメソッドでの連鎖
  • エラー処理
  • エラーの表現と Throw
    エラーの処理
    throw 関数を使用したエラーの伝播
    Do-Catch を使用したエラー処理
    エラー をOptional の値に変換
    エラー伝播を無効に
    クリーンアップアクションの指定
  • 型キャスト
  • 型キャストのためのクラス階層の定義
    型のチェック
    ダウンキャスト
  • Any と AnyObjecgt 用の型キャスティング
  • ネストした型
  • 実際のネストした型
    ネストした型への参照
  • 拡張機能
  • 拡張機能の構文
    計算されたプロパティ
    イニシャライザ
  • メソッド
  • 変異インスタンスメソッド
    サブスクリプト
    ネストした型
  • プロトコル
  • プロトコルの構文
    プロパティの要件
    メソッドの要件
    変異メソッドの要件
  • イニシャライザの要件
  • プロトコルイニシャライザ要件のクラス実装
    失敗可能イニシャライザの要件
    型としてのプロトコル
    デリゲート
  • 拡張機能を持つプロトコル準拠の追加
  • 拡張機能を持つプロトコルの採用を宣言
    プロトコル型のコレクション
    プロトコルの継承
    クラス専用プロトコル
    プロトコルの構成
    プロトコル準拠の確認
    Optional のプロトコル要件
  • プロトコル拡張機能
  • デフォルトの実装の提供
    プロトコル拡張機能に制約を追加
  • ジェネリック(汎用)
  • 汎用が解決する問題
    汎用関数
    型パラメータ
    型パラメータの命名
    汎用の型
    汎用型の拡張
  • 型の制約
  • 型制約の構文
    実際の型の制約
  • 関連型
  • 実際の関連型
    既存の型を拡張して関連型を指定
    型注釈を使用して関連型を制約
    汎用の Where 句
    汎用の Where 句を含む拡張機能
    関連する型と汎用の Where 句
    汎用のサブスクリプト
  • 自動参照カウント
  • どのように ARC は働くか
    実際の ARC
    クラスインスタンス間の強い循環参照
  • クラスインスタンス間の強い循環参照の解決
  • 弱い参照
    所有されていない参照
    所有されていない参照と暗黙に開封された Optional のプロパティ
    クロージャの strong な循環参照
  • クロージャの strong な循環参照の解決
  • キャプチャリストの定義
    弱い参照と所有されていない参照
  • メモリの安全性
  • メモリへのアクセス競合の理解
    メモリアクセスの特徴
    In-Out パラメータへのアクセスの競合
    メソッド内の Self へのアクセスの競合
    プロパティへのアクセスの競合
  • アクセス制御
  • モジュールとソースファイル
  • アクセスレベル
  • アクセスレベルの全体的指針
    デフォルトのアクセスレベル
    ターゲット一つのアプリのアクセスレベル
    フレームワークのアクセスレベル
    ユニットテストのターゲット用のアクセスレベル
    アクセス制御の構文
  • カスタム型
  • タプル型
    関数型
  • 列挙型
  • 生の値と関連する値
    ネストした型
    サブクラス化
  • 定数、変数、プロパティ、およびサブスクリプト
  • ゲッタとセッタ
  • イニシャライザ
  • デフォルトのイニシャライザ
    構造体型用のデフォルトメンバ化イニシャライザ
  • プロトコル
  • プロトコルの継承
    プロトコルの準拠
  • 拡張機能
  • 拡張機能の private メンバ
    汎用
    型エイリアス
  • 高度な演算子
  • ビット単位演算子
  • ビット単位の NOT 演算子
    ビット単位の AND 演算子
    ビット単位の OR 演算子
    ビット単位の XOR 演算子
  • ビット単位の左と右シフト演算子
  • 符号なし整数のシフト動作
    符号付き整数のシフト動作
  • オーバーフロー演算子
  • 値オーバーフロー
    優先順位と結合性
  • 演算子メソッド
  • 接頭辞と接尾辞演算子
    複合代入演算子
    等価演算子
  • カスタム演算子
  • カスタム挿入辞演算子の優先順位
  • 言語のガイド(Part III)
  • 言語リファレンスについて
  • 文法の読み方
  • 語彙の構造
  • 空白とコメント
    識別子
    キーワードと句読点
  • リテラル
  • 整数リテラル
    浮動小数点リテラル
    文字列のリテラル
    演算子

  • 型注釈
    型識別子
    タプル型
    関数型
    エスケープしないクロージャの制限事項
    配列型
    辞書型
    Optional の型
    暗黙に開封された Optional の型
    プロトコル構成の型
    メタタイプ型
    型の継承句
    型の推測

  • 接頭辞式
    Try 演算子
  • 二項式
  • 代入演算子
    三項条件演算子
    型キャスト演算子
  • 一次式
  • リテラル式
    Self 式
    スーパークラス式
  • クロージャ式
  • キャプチャ・リスト
    暗黙のメンバ式
    括弧で囲まれた式
    タプル式
    ワイルドカード式
    キーパス式
    セレクタ式
    キーパス文字列式
  • 接尾辞の式
  • 関数呼び出し式
    イニシャライザ式
    明示的なメンバ式
    接尾辞の Self 式
    サブスクリプト 式
    強制値の式
    Optional の連鎖式

  • ループ文
  • For-In 文
    While 文
    Repeat-While 文
  • 分岐文
  • if 文
    Guard 文
  • switch 文
  • switch 文は、網羅的である必要あり
    実行が暗黙的に case を Fall Through しない
    ラベル付き文
  • 制御転送文
  • break 文
    continue 文
    fallthrough 文
    return 文
    throw 文
    defer 文
    do 文
  • コンパイラ制御文
  • 条件コンパイルブロック
    行制御文
    利用可能条件
  • 宣言
  • トップレベルのコード
    コードブロック
    Import 宣言
    ­定数の宣言
  • 変数の宣言
  • 格納された変数と格納された変数のプロパティ
    計算された変数と計算されたプロパティ
    格納された変数監視者とプロパティの監視者
    型変数プロパティ
    型エイリアス宣言
  • 関数の宣言
  • パラメータ名
    In-Out パラメータ
    パラメータの特殊な種類
    メソッドの特殊な種類
    Throw する関数とメソッド
    Rethrow する関数とメソッド
    決して返さない関数
  • 列挙型の宣言
  • 任意の型の case を列挙
  • 間接による列挙
    生の値型の case を列挙
    列挙型 case へのアクセス
    構造体の宣言
    クラスの宣言
  • プロトコルの宣言
  • プロトコル・プロパティ宣言
    プロトコル・メソッド宣言
    プロトコル・イニシャライザ宣言
    プロトコル・サブスクリプト宣言
    プロトコルに関連した型の宣言
  • イニシャライザ宣言
  • 失敗可能イニシャライザ
    デイニシャライザ宣言
    拡張機能の宣言
    サブスクリプト宣言
    演算子の宣言
    優先順位グループ宣言
  • 宣言修飾子
  • アクセス制御レベル
  • 属性
  • 宣言の属性
  • インターフェイスビルダーで使われる宣言属性
    型の属性
  • パターン
  • ワイルドカードパターン
    識別子パターン
    値結合パターン
    タプルパターン
    列挙型 case パターン
    Optional のパターン
    型キャストパターン
    式のパターン
  • 汎用パラメータと引数
  • 汎用パラメータ句
  • 汎用の where 句
    汎用引数句
  • 文法のまとめ
  • 語彙の構造



    宣言
    属性
    パターン
    汎用パラメータと引数
  • マニュアルの変更履歴
  • 変更履歴












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)