Genericsについて調べた


[Generics | The Swift Programming Language](https://developer.apple.com/library/ios/documentation/swift/conceptual/Swift_Programming_Language/Generics.html)

SwiftのGenericsについて調べました。Playgroundで実行しながら調べましたが、間違ってるところとかあったら指摘してくださるとありがたいです。

## Genericsが解決している課題

例えば、Genericsが無い場合、2つの変数を入れ替えるswapっていう関数を作る時、静的片付け言語だと型ごとに関数を用意しないと実現できない。

```swift
// 第1引数と第2引数を入れ替える関数
func swapInt (inout a:Int, inout b:Int) {
	let temp:Int = a
	a = b
	b = temp
}

// 型が違うだけで中身はswapIntとほぼ同じ関数
func swapString (inout a:String, inout b:String) { ... }
func swapDouble (inout a:Double, inout b:Double) { ... }

```

Genericsは型変数（Type Parameters）を宣言時にプレースホルダとして使うことで、具体的な型を指定しなくても関数宣言できる。

```swift
// Tが型変数
func swapTwoValues<T> (inout a:T, inout b:T) {
	let temp:T = a
	a = b
	b = tmp
}

// String
var aString = "A String"
var bString = "B String"

swapTwoValues(&aString, &bString)

// Double
var aDouble = 0.0001
var bDouble = 0.1

swapTwoValues(&aDouble, &bDouble)
```

## 基本的な宣言の仕方とか

```swift
// 返り値の型にも使用可能
func hoge<T> (a: T) -> T { ... }

// 複数指定する場合にはカンマ区切り
func hoge<T1, T2, T3, T4>() { ...  }

// クラスだとこんな感じ
class Hoge<T> {
	var value: T
	
	init(value: T) {
		self.value = value
	}

	func get () -> T {
		return value
	}
}

// 構造体だとこんな感じ
struct Hoge<T> {
	var value: T

	func get () -> T {
		return value
	}
}
```

## 型変数の名前

型変数は伝統的に大文字1文字らしい（JavaもTだったような）が、小文字でも動いた。あと、Stringとか既存の型と被っていてもPlaygroundでは動いた（使わないと思うけど）

```swift
// 型変数名：String
func swapTwoValues2<String> (inout a: String, inout b: String) {
    let temp: String = a
    a = b
    b = temp
}

// Double
var aDouble = 0.0001
var bDouble = 0.1

swapTwoValues2(&aDouble, &bDouble)

aDouble // 0.1
bDouble // 0.0001

```

## extension内部から型変数を参照

extensionからも型変数にアクセス可能。

```swift
// Tという名前で型変数を定義しているクラス
class KeyValue<T> {
    var key: String
    var value: T
    
    init(key: String, value: T) {
        self.key = key
        self.value = value
    }
}

// extensionでKeyValueクラスを拡張
extension KeyValue {
	// extension内でもTで参照できる
	func get() -> T {
		return value
	}
}

var kv = KeyValue(key: "hoge", value: "fuga")
kv.get() // "fuga"
```

## 型の制限

今までのサンプルコードだと型変数Tにはどんな型でもOKだよーみたいな感じの宣言だったが、型を指定して型変数に入る型を制限することも可能。

### クラスで制限する例

```swift
// 親クラス
class A {
    var val: String

    init (val: String) {
        self.val = val
    }
    
    func get() -> String {
        return val
    }
}

// 子クラス
class B : A{
    override func get() -> String {
        return "B Class"
    }
}

// TはAクラスまたはその子ならOK
func getAValue<T: A>(obj: T) -> String {
    return obj.get()
}

var aObj = A(val: "A")
getAValue(aObj) // "A"

var bObj = B(val: "A")
getAValue(bObj) // "B Class"
```

## protocolのAssociated Types

protocolにも型をプレースホルダするAssociated Types（日本語で言うと関連型？）という機能があり、`typealias 名前`という感じで指定する

```swift
protocol Gettable {
    typealias ItemType
    // getの返り値の型が不定になってる
    func get() -> ItemType
}
```

で、protocol実装時にIteｍTypeの型が決まる

```swift
struct StringGetter: Gettable {
    // 明示的にStringにする
    typealias ItemType = String

    var value: String
    func get() -> String {
        return value
    }
}

// 明示的に指定しなくてもgetの返り値がStringなのでItemTypeがStringになる
struct StringGetter: Gettable {
    var value: String
    func get() -> String {
        return value
    }
}
```

## Associated Typesを活用

型変数にどの型が入ったのかはわからないので、「第1引数と第2引数のTの型が一緒じゃないと嫌だ」とか「しかもその型はStringじゃないとだめや」というのはGenericsだけだと実現できない。

が、protocolのAssociated Typesとwhere句を使うとできる。

```swift
struct Fuga<T>: Gettable {
    var value: T

    // Gettableのgetを実装しているので
    // FugaのItemTypeはTで、
    // このstructを生成するときにどの型を使うかで
    // ItemTypeが変動する
    func get() -> T {
        return value
    }
}

// getの返り値の型が一致してないとダメ！
// getの返り値の方はStringじゃないとダメ！
func getStrings<T1: Gettable, T2: Gettable where T1.ItemType == T2.ItemType, T1.ItemType == String> (a : T1, b : T2) -> [T1.ItemType] {
    return [a.get(), b.get()]
}

var a = Fuga(value: "a");
var b = StringGetter(value: "b");

getStrings(a, b) // ["a", "b"]

var c = Fuga(value: 10000);
getStrings(a, c)  // エラー！！！
```

## つかいどころをもっと知りたい

サンプルコードは実用性の無いコードばかりなので、こういうとこで使うとええでっていうのがあったらぜひ教えて欲しいです。