Swiftのジェネリックスについてのメモ


自分がジェネリックスという単語自体が初めて聞く言葉であり、
よく理解できてないのでまとめてみた

参照：[The Swift Programming Language (iBooks)](https://itunes.apple.com/jp/book/swift-programming-language/id881256329?mt=11)

## Genericsとは

クラスや関数を使う側が扱う型を指定できるようにする仕組み
これにより、抽象的なコードを記述することを可能にする


## 関数でのGenerics

関数内で使用する任意の型を定義できる

### 1. 型制約なし

型の制約がないので、どんな型の場合でも使用することができる
任意の型は名前は自由(ただし、UpperCamelCaseであること)

```
func 関数名 <任意の型> () {
	// 任意の型を使用した処理
}
```

#### 例) ItemTypeという任意の型を引数と戻り値と内部で使用している

``` Swift
func repeat<ItemType>(item: ItemType, times: Int) -> ItemType[] {
    var result = ItemType[]()
    for i in 0..times {
        result += item
    }
    return result
}

// ItemTypeがStirngの場合
repeat("knock", 4)    // ["knock", "knock", "knock", "knock"]

// ItemTyoeがIntの場合
repeat(10, 4)         // [10, 10, 10, 10]


抜粋：: Apple Inc. “The Swift Programming Language”。 iBooks. https://itun.es/jp/jEUH0.l

```



### 2. 型制約あり

```
func 関数名 <任意の型: クラス名 または プロトコル名> () {
	// 任意の型を使用した処理
}
```

#### 例) 使用できる型(T)がEquatableプロトコルに準拠した型だけに制限される

``` Swift
func findIndex<T: Equatable>(array: T[], valueToFind: T) -> Int? {
    for (index, value) in enumerate(array) {
        if value == valueToFind {
            return index
        }
    }
    return nil
}

抜粋：: Apple Inc. “The Swift Programming Language”。 iBooks. https://itun.es/jp/jEUH0.l
```


## 構造体でのGenerics

クラス、構造体、列挙で使用する任意の型を定義することができる

#### 例) 任意の型の値の要素を持つスタック

``` Swift
struct Stack<T> {
    var items = T[]()
    mutating func push(item: T) {
        items.append(item)
    }
    mutating func pop() -> T {
        return items.removeLast()
    }
}

var stack = Stack<String>()  // <String>と記述することで"String型"で指定する
stack.push("A")
stack.push("B")
stack.items    // ["A", "B"]

stack.push(100) // String以外受け付けないのでエラー

抜粋：: Apple Inc. “The Swift Programming Language”。 iBooks. https://itun.es/jp/jEUH0.l
```

## プロトコルでのGenerics 

プロトコル内で使用する任意の型を定義できる
このとき、`typealias `に任意の型名を指定しておく

#### 例) ItemTypeという任意の型を使用しているプロトコル

プロトコルの宣言

``` Swift
protocol Container {
    typealias ItemType
    mutating func append(item: ItemType)
    var count: Int { get } // { get }はgetter処理の実装を必須とする
    subscript(i: Int) -> ItemType { get }
}

抜粋：: Apple Inc. “The Swift Programming Language”。 iBooks. https://itun.es/jp/jEUH0.l
```

Containerプロトコルに準拠した構造体
ここで任意の型をIntとして固定

```

// 任意の型をIntとして実装
struct IntStack: Container {
    // original IntStack implementation
    var items = Int[]()
    mutating func push(item: Int) {
        items.append(item)
    }
    mutating func pop() -> Int {
        return items.removeLast()
    }
    // conformance to the Container protocol
    typealias ItemType = Int
    mutating func append(item: Int) {
        self.push(item)
    }
    var count: Int {
        return items.count
    }
    subscript(i: Int) -> Int {
        return items[i]
    }
}

抜粋：: Apple Inc. “The Swift Programming Language”。 iBooks. https://itun.es/jp/jEUH0.l
```

こちらはGenericsの構造体にContainerプロトコルを準拠させたパターン
こちらは、typealiasにセットはしていないが、
任意の型(T型)をitemとappendとsubscriptで使用していることから、
ItemTypeとしてT型を使用していることが推測できる

```
struct Stack<T>: Container {
    // original Stack<T> 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]
    }
}

抜粋：: Apple Inc. “The Swift Programming Language”。 iBooks. https://itun.es/jp/jEUH0.l
```


## whereを使った型指定

型指定にプロトコルを指定するときに、
さらに、そのプロトコルの内容で細かく制限をかけることができる

#### 例) 

Containerプロトコルを実装したC1とC2という型で指定
それ以外に以下の指定を行う

* C1のItemTypeにEquatableプロトコルの型が入っていること
* C1のItemTypeとC2のItemTypeが同じ型であること
 

``` Swift
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..someContainer.count {
            if someContainer[i] != anotherContainer[i] {
                return false
            }
        }
        
        // all items match, so return true
        return true
        
}

抜粋：: Apple Inc. “The Swift Programming Language”。 iBooks. https://itun.es/jp/jEUH0.l
```