Swiftプログラミングにおける汎用解析

9969 ワード

汎用コードは、自己ニーズに応じて定義され、任意のタイプに適用され、柔軟で再利用可能な関数とタイプを書くことができます.重複するコードを避け、コードの意図を明確かつ抽象的に表現することができます.  汎用はSwiftの強力な特徴の一つであり、多くのSwift標準ライブラリは汎用コードによって構築されています.実際、汎用的な使用は言語マニュアル全体を貫いていますが、あなたは発見していません.たとえば、Swiftの配列と辞書のタイプは、汎用セットです.Int配列を作成したり、String配列を作成したり、他のSwiftのタイプのデータ配列であったりすることができます.同様に、指定したタイプの辞書(dictionary)を作成することもできます.また、これらのタイプには制限はありません.  汎用的に解決された問題ここでは、2つのInt値を交換するための標準的な非汎用関数swapTwoIntsです.
 
  
func swapTwoInts(inout a: Int, inout b: Int)
    let temporaryA = a
    a = b
    b = temporaryA
}

この関数は、書き込み読み出し(in-out)パラメータを用いてaとbの値を交換します.書き込み読み出しパラメータを参照してください.
 
swapTwoInts関数はbの元の値をaに交換したり、aの元の値をbに交換したりすることができます.この関数を呼び出して2つのInt変数の値を交換することができます.
 
  
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
println("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// "someInt is now 107, and anotherInt is now 3"
swapTwoInts , Int , String Double, , swapTwoStrings swapTwoDoublesfunctions, :
func swapTwoStrings(inout a: String, inout b: String) {
    let temporaryA = a
    a = b
    b = temporaryA
}
 
func swapTwoDoubles(inout a: Double, inout b: Double) {
    let temporaryA = a
    a = b
    b = temporaryA
}

swapTwoInts、swapTwoStrings、swapTwoDoubles関数の機能は同じであることに気づくかもしれませんが、唯一の違いは、Int、String、Doubleの変数タイプが異なることです.
 
しかし、実際の応用では、通常、より強力で、可能な限り柔軟性を考慮した単一の関数が必要です.2つの任意のタイプの値を交換することができます.幸いなことに、汎用コードはこの問題を解決します.(このような汎用関数は後で定義されています.)
 
注意:すべての3つの関数では、aとbのタイプは同じです.aとbが同じタイプでない場合、それら2つは値を交換できません.Swiftはタイプが安全な言語なので、Stringタイプの変数とDoubleタイプの変数が値を交換することは許可されません.必ずしなければならない場合、Swiftはコンパイルエラーを報告します.
汎用関数:タイプパラメータ汎用関数は、「Int」または「String」などの任意のデータ型にアクセスできます.
 
  
func exchange(inout a: T, inout b: T) {
   let temp = a
   a = b
   b = temp
}

var numb1 = 100
var numb2 = 200

println("Before Swapping Int values are: \(numb1) and \(numb2)")
exchange(&numb1, &numb2)
println("After Swapping Int values are: \(numb1) and \(numb2)")

var str1 = "Generics"
var str2 = "Functions"

println("Before Swapping String values are: \(str1) and \(str2)")
exchange(&str1, &str2)
println("After Swapping String values are: \(str1) and \(str2)")


Playgroundを使用して上記のプログラムを実行すると、以下の結果が得られます.

Before Swapping Int values are: 100 and 200
After Swapping Int values are: 200 and 100
Before Swapping String values are: Generics and Functions
After Swapping String values are: Functions and Generics

関数exchange()は、上記のスキームで説明され、タイプパラメータ値として使用されるものと交換するために使用される.これは初めてで、関数exchange()が呼び出されてInt値を返し、2回目の関数exchange()がString値を返します.複数のパラメータタイプには、括弧で区切られたカンマを含めることができます.
タイプパラメータは、タイプパラメータを持つ目的を理解するためにユーザー定義として命名されます.Swiftは汎用型パラメータとしての名前を提供する.ただし、イメージ配列やディクショナリパラメータは、キー、値として名前を付けて、入力がディクショナリに属することを決定することもできます.
汎用タイプ
 
  
struct TOS {
   var items = [T]()
   mutating func push(item: T) {
      items.append(item)
   }
  
   mutating func pop() -> T {
      return items.removeLast()
   }
}

var tos = TOS()
tos.push("Swift")
println(tos.items)

tos.push("Generics")
println(tos.items)

tos.push("Type Parameters")
println(tos.items)

tos.push("Naming Type Parameters")
println(tos.items)


let deletetos = tos.pop()


Playgroundを使用して上記のプログラムを実行すると、以下の結果が得られます.

[Swift]
[Swift, Generics]
[Swift, Generics, Type Parameters]
[Swift, Generics, Type Parameters, Naming Type Parameters]

拡張汎用タイプ拡張スタックプロパティは、プロジェクトの上部にextensionキーが含まれていることを知っておく必要があります.
 
  
struct TOS {
   var items = [T]()
   mutating func push(item: T) {
      items.append(item)
   }

   mutating func pop() -> T {
      return items.removeLast()
   }
}

var tos = TOS()
tos.push("Swift")
println(tos.items)

tos.push("Generics")
println(tos.items)

tos.push("Type Parameters")
println(tos.items)

tos.push("Naming Type Parameters")
println(tos.items)

extension TOS {
   var first: T? {
      return items.isEmpty ? nil : items[items.count - 1]
   }
}

if let first = tos.first {
   println("The top item on the stack is \(first).")
}


Playgroundを使用して上記のプログラムを実行すると、以下の結果が得られます.

[Swift]
[Swift, Generics]
[Swift, Generics, Type Parameters]
[Swift, Generics, Type Parameters, Naming Type Parameters]

スタックの上部にあるプロジェクト名のタイプパラメータ.
タイプ制約Swift言語では、タイプ制約で特定のクラスからタイプパラメータを継承するか、プロトコルの一貫性基準を確保するかを指定できます.
 
  
func exchange(inout a: T, inout b: T) {
   let temp = a
   a = b
   b = temp
}

var numb1 = 100
var numb2 = 200

println("Before Swapping Int values are: \(numb1) and \(numb2)")
exchange(&numb1, &numb2)
println("After Swapping Int values are: \(numb1) and \(numb2)")

  
var str1 = "Generics"
var str2 = "Functions"

println("Before Swapping String values are: \(str1) and \(str2)")
exchange(&str1, &str2)
println("After Swapping String values are: \(str1) and \(str2)")


Playgroundを使用して上記のプログラムを実行すると、以下の結果が得られます.

Before Swapping Int values are: 100 and 200
After Swapping Int values are: 200 and 100
Before Swapping String values are: Generics and Functions
After Swapping String values are: Functions and Generics

関連タイプSwiftは、関連タイプを許可し、キーワード「typealias」プロトコルによって内部宣言を定義できます.
 
  
protocol Container {
   typealias ItemType
   mutating func append(item: ItemType)
   var count: Int { get }
   subscript(i: Int) -> ItemType { get }
}

struct TOS: Container {
   // original Stack implementation
   var items = [T]()
   mutating func push(item: T) {
      items.append(item)
   }
  
   mutating func pop() -> T {
      return items.removeLast()
   }

   // conformance to the Container protocol
   mutating func append(item: T) {
      self.push(item)
   }
  
   var count: Int {
      return items.count
   }

   subscript(i: Int) -> T {
      return items[i]
   }
}

var tos = TOS()
tos.push("Swift")
println(tos.items)

tos.push("Generics")
println(tos.items)

tos.push("Type Parameters")
println(tos.items)

tos.push("Naming Type Parameters")
println(tos.items)


Playgroundを使用して上記のプログラムを実行すると、以下の結果が得られます.

[Swift]
[Swift, Generics]
[Swift, Generics, Type Parameters]
[Swift, Generics, Type Parameters, Naming Type Parameters]

Where句タイプ制約を使用すると、汎用関数またはタイプに関連付けられたタイプのパラメータ要件を定義できます.関連するタイプを定義する「where」句は、タイプパラメータリストの一部の要件として宣言されます.「where」キーワードタイプパラメータの後ろのタイプと関連タイプの間の関連タイプの制限、平等関係のリストの後に配置されます.
 
  
 protocol Container {
   typealias ItemType
   mutating func append(item: ItemType)
   var count: Int { get }
   subscript(i: Int) -> ItemType { get }
}

struct Stack: Container {
   // original Stack implementation
   var items = [T]()
   mutating func push(item: T) {
      items.append(item)
   }

   mutating func pop() -> T {
      return items.removeLast()
   }

   // conformance to the Container protocol
   mutating func append(item: T) {
      self.push(item)
   }
  
   var count: Int {
      return items.count
   }

   subscript(i: Int) -> T {
      return items[i]
   }
}

func allItemsMatch<
   C1: Container, C2: Container
   where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
   (someContainer: C1, anotherContainer: C2) -> Bool {
   // check that both containers contain the same number of items
   if someContainer.count != anotherContainer.count {
      return false
}

// check each pair of items to see if they are equivalent
for i in 0..    if someContainer[i] != anotherContainer[i] {
      return false
   }
}
      // all items match, so return true
      return true
}

var tos = Stack()
tos.push("Swift")
println(tos.items)

tos.push("Generics")
println(tos.items)

tos.push("Where Clause")
println(tos.items)

var eos = ["Swift", "Generics", "Where Clause"]
println(eos)


Playgroundを使用して上記のプログラムを実行すると、以下の結果が得られます.

[Swift]
[Swift, Generics]
[Swift, Generics, Where Clause]
[Swift, Generics, Where Clause]