Swiftらしいコーディングを学ぶ 「Generics」

# はじめに
SwiftのドキュメントやOSS見るとGenericsがよく使われてますね。Genericsが使われた関数や型を理解したり柔軟で汎用的なコーディングをしていくためにもGenericsは学んでいくべきだと思います。今回はGenericsについて学んでいきたいと思います。

# Generics
[Generics in Swift, Part 2](http://austinzheng.com/2015/09/29/swift-generics-pt-2/)の***Why generics?***では、Genericsを使う理由として以下の3つが挙げられています。

- ***Type safety*** 
- ***Less code duplication***
- ***Library flexibility***

Genericsを用いることで指定した要件、もしくは任意の様々な型を扱うことができるので、柔軟で再利用可能な型や関数を定義することができます。
`Array`や`Dictionary`もGenericsなCollectionです。（詳しくは[Swiftらしいコーディングを学ぶ 「CollectionType」](http://qiita.com/shoheiyokoyama/items/429a7aeef5836e764bb8)参照）例えば、`Array`に格納する要素は`Int`や`String`や制限なく様々な型で生成することができますね。普段当たり前のように利用しているこれらのクラスやSwiftの標準ライブラリはGenericsが利用され、柔軟に型を指定することができます。

Genericsは***Generic Functions***と***Generic Types***に大別することができます。まずは、Generic Typesからみていきたいと思います。


# Generic Types

クラスや構造体、列挙体でGenericsを使用して、様々な型で動作する汎用的な型を定義することができます。この時のGenericsを使用して定義された型を***Generic Types***(ジェネリック型)と呼びます。


## 構造体・クラス

一般的にクラスや構造体にGenericsを用いる際は次のように記述します。

```swift:Struct
struct StructName<TypeParameter> {
    //struct statements
}

var struct = StructName<TypeParameter>()
```

```swift:Class
class ClassName<TypeParameter> {
    //Class statements
}
var class = ClassName<TypeParameter>()
```

クラスも構造体も使い方は同じですね。`TypeParameter`の部分に型を明記します。慣例として`T`や`U`が使われることが多いですが、実際に利用する場合は分かりやすい名前で定義し、***UpperCamelCase***にすることが推奨されています。
実際に要素を格納/取り除く構造体`Queue`を定義してみます。

```swift
struct Queue<Element> {
    private var elements = [Element]()
    
    mutating func enqueue(newElement: Element) {
        elements.append(newElement)
    }
    mutating func dequeue() -> Element? {
        guard !elements.isEmpty else { return nil }
        return elements.removeAtIndex(0)
    }
}

var intQueue = Queue<Int>()
intQueue.enqueue(3)//[3]
intQueue.enqueue(5)//[3, 5]
intQueue.dequeue()//3 elements=>[5]
intQueue.dequeue()//5 elements=>[]
intQueue.dequeue()//nil

var stringQueue = Queue<String>()
stringQueue.enqueue("Generics")//["Generics"]
stringQueue.enqueue("Generic Types")//["Generics", "Generic Types"]
```

このように、インスタンス化する際に利用する型を明記すれば、様々な型で利用できるんですね。`<TypeParameter>`の部分で定義した`TypeParameter`は上記のように構造体の内部で利用できます。このように汎用的な型を指定することによって様々な型に対応できるんですね。

## Extending a Generic Type
Genericsを用いたクラス・構造体は拡張することができます。拡張する場合は、`<TypeParameter>`の記述は必要ないです。

```swift
extension Queue {
    func peek() -> Element? {
        return elements.first
    }
}

stringQueue.peek()//"Generics"
```

## Class Inheritance
Genericsを用いたクラスは、継承が可能です。

```swift
class BaseClass<T> {}
class InheritClass<T>: Box<T> {}

//TypeParameterの名前は変えられるが、親クラスと揃える必要がある
class InheritClass<U>: Box<U> {}//○
class InheritClass<U>: Box<T> {}//×

class StringClass: BaseClass<String> {}
```
継承したサブクラスでもGenericsを使用する場合は`<TypeParameter>`の記述が必要です。型を明示する場合は親クラスに型を明示する必要があります。

## Associated Types

protocolにもGenericsを利用することができます。[The Swift Programming Language (Swift 2.2)](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Generics.html)の例がわかりやすいかと思います。
まず、`Container`という名前のprotocolを見てみましょう。

```swift
protocol Container {
    associatedtype ItemType

    mutating func append(item: ItemType)
    var count: Int { get }
    subscript(i: Int) -> ItemType { get }
}
```

protocolでGenericsを利用する際は`associatedtype`でGenericsを宣言します。ここでは`ItemType`という汎用的な型が定義されてますね。
`Container`プロトコルを利用する場合は以下のルールに準拠しなければならないことになります。

- `append`メソッドは引数に`ItemType`を利用しなければならない
- countは`Int`型を返さなければならない
- `subscript`によって返される型は`ItemType`でなければならない


### Non-generic type

実際に`Container`を利用してみましょう。`Container`に準拠した`IntStack`という構造体を定義してみます。

```swift
struct IntStack: Container {
    var items = [Int]()
    
    typealias ItemType = Int
    mutating func append(item: Int) {
        items.append(item)
    }
    mutating func pop() -> Int {
        return items.removeLast()
    }
    
    var count: Int {
        return items.count
    }
    subscript(i: Int) -> Int {
        return items[i]
    }
}
```

重要な部分は`typealias ItemType = Int`の部分です。`ItemType`を`Int`型に宣言することで`ItemType`を構造体の中で`Int`型として利用することができます。

```swift
var intStack = IntStack()
intStack.append(2)
intStack.append(3)
intStack.append(4)

intStack.count//3
intStack[2]//4
```


### Generic types

`associatedtype `は`Generic types`にも利用することができます。
先ほど定義した`Queue`構造体に`Container`を準拠させてみましょう。

```swift
struct Queue<Element>: Container {
    private var elements = [Element]()
    
    mutating func enqueue(newElement: Element) {
        elements.append(newElement)
    }
    mutating func dequeue() -> Element? {
        guard !elements.isEmpty else { return nil }
        return elements.removeAtIndex(0)
    }
    
    mutating func append(item: Element) {
        enqueue(item)
    }
    var count: Int {
        return elements.count
    }
    subscript(i: Int) -> Element {
        return elements[i]
    }
}
```

このように`ItemType`の部分にGenerics Typeである`Element`を利用することができ、様々な型に対応することができます。

```swift
var intQueue = Queue<Int>()
intQueue.append(3)//[3]
intQueue.append(5)//[3, 5]
intQueue[1]//5
intQueue.count//2

var stringQueue = Queue<String>()
stringQueue.append("Generics")//["Generics"]
stringQueue.append("Generic Types")//["Generics", "Generic Types"]
stringQueue[0]//"Generics"
stringQueue.count//2
```


# Generic Functions
***Generic Functions***（ジェネリック関数）は、汎用的に様々な型で利用できる関数のことです。一般的に次のように定義します。

```swift
func functionName<PlaceholderTypeName,..>(paramerters:PlaceholderTypeName,...)
```

`Int`や`String`などの実際の型の代わりに`Type Parameters`として`PlaceholderTypeName`を定義し、関数名の後に`<>`で囲んで記述します。
例えば、`Dictionary`では`Dictionary<Key, Value>`, `Array`では` Array<Element>`という`PlaceholderTypeName`が利用されていますね。

それでは、具体的な例で見ていきましょう。[The Swift Programming Language (Swift 2.2)
](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Generics.html)の引数を入れ替える関数の例がわかりやすいと思います。まずはGenericを使用していない関数を見てみましょう。以下は、`Int`型の引数を入れ替える関数です。

```swift
func swapTwoInts(inout a: Int, inout _ b: Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}
```
`swapTwoInts`は参照渡しなので`someInt`と`anotherInt`が入れ替わっていますね。

```swift
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// Prints "someInt is now 107, and anotherInt is now 3"
```
しかし、`Int`以外で入れ替える処理をしたい場合は型の数だけ関数を定義する必要があり、[DRYの原則](https://ja.wikipedia.org/wiki/Don%27t_repeat_yourself)に反しています。

```swift
//他の型で使用するためには、それぞれの型を指定しなければならない
func swapTwoInts(inout a: Int, inout _ b: Int)
func swapTwoDouble(inout a: Double, inout _ b: Double)
func swapTwoString(inout a: String, inout _ b: String)
```

今度はこの関数を`Generic Functions`を利用して定義してみます。

```swift
func swapTwoValues<T>(inout a: T, inout _ b: T) {
    let temporaryA = a
    a = b
    b = temporaryA
}
```

このGeneric Functionsに`Int`や`String`を引数に渡してみます。

```swift
var someInt = 3
var anotherInt = 107
swapTwoValues(&someInt, &anotherInt)
print("someInt is \(someInt), anotherInt is \(anotherInt)")
// someInt is 107, anotherInt is 3

var someString = "hello"
var anotherString = "world"
swapTwoValues(&someString, &anotherString)
print("someString is \(someString), anotherString is \(anotherString)")
//someString is world, anotherString is hello

var someDouble: Double = 2.5
var someFloat: Float = 3.54
swapTwoValues(&someDouble, &someFloat)
//Cannot convert value of type 'inout Double' to expected argument type 'inout _'
```

異なる型を引数にしても正常に動作しているのがわかるかと思います。このように`Generic Functions`を使用することで様々な型に柔軟に対応できるんですね。`inout a: T, inout _ b: T`の部分で引数`a`と`b`は`T`の型で定義してあるので、異なる型を引数に入れるとエラーになっていますね。複数の型を定義する場合は`func functionName<T, U>(a: t, b: U)`のように定義します。
`T`のような`Type Parameters`は引数だけではなく、返り値、関数内の定義としても利用できます。上の例では、`T`が`Int`や`String`に置き換わっているんですね。

## Type Constraints

ジェネリック関数に用いる`Type Parameters`には制約を持たせることができます。一般的に次のように記述します。

```swift
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
    // function body goes here
}
```

このように`Type Parameters`が特定のサブクラスだったり`Protocol`に準拠しなければいけないという制約をつけることができるんですね。
これは実際の例で見ていくとわかりやすいかと思います。まずは制約を持たせていないジェネリック関数をみていきたいと思います。次のジェネリクス関数は配列の中の一番大きいものを返す関数です。

```swift
func findLargestInArray<T>(array: [T]) -> T? {
    if array.isEmpty { return nil }
    
    var largestValue = array.first
    array.forEach { val in
        //Compiler Error
        largestValue = val > largestValue ? val : largestValue
    }
    return largestValue
}
```

このジェネリクス関数では、以下のエラーが出てしまいます。
```
Binary operator '>' cannot be applied to operands of type '_' and 'T?'
```
`T`型の要素は`>`の関数を持っているかわからず比較できるかわからないよ！と怒られてしましました。`T`型は比較することができる`Comparable`に準拠してなくてはならないんですね。次は型に制約をつけてみます。

```swift
func findLargestInArray<T: Comparable>(array: [T]) -> T? {
    if array.isEmpty { return nil }
    
    var largestValue = array.first
    array.forEach { val in
        largestValue = val > largestValue ? val : largestValue
    }
    return largestValue
}
```
Compilerが通りましたね。型に制約をつけたことで`T`が`Comparable`に準拠するので、`T`が`>`関数を持っていることが担保されるというわけです。

```swift
let array = [1, 2, 3, 5, 7, 10]
let largestValue = findLargestInArray(array)
print(largestValue)//10
```

## Where Clauses
ジェネリクス関数はさらに`Where`を用いて制約をつけることができます。先ほどの`Container`を使って制約をつけてみましょう。

```swift
protocol Container {
    associatedtype ItemType

    mutating func append(item: ItemType)
    var count: Int { get }
    subscript(i: Int) -> ItemType { get }
}
```

`Where`を用いて次のように制約をつけることができます。

```swift
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
        }
    }
    return true
}
```

型制約の部分ですが、順を追って見てみましょう。

- `C1: Container, C2: Container`
この部分は先ほども確認しましたが、C1の型とC2は`Container`Protocolに準拠していなければならないということですね。

- `where C1.ItemType == C2.ItemType`
この部分は`C1`の`ItemType`型は`C2`の`ItemType`と同じ型でなければならないということです。

- `C1.ItemType: Equatable`
`C1`の`ItemType`は`Equatable`プロトコルに準拠してなくてはいけないということです。必然的に`C2`の`ItemType`も`Equatable`に準拠することになりますね。

## Whereを用いて拡張してみる
実際にWhereを用いて実践してみたいと思います。`CollectionType`を拡張して一番大きいものを返す`largestValue ()`を実装してみましょう。
`Collection Type`は[Swiftらしいコーディングを学ぶ 「CollectionType」](http://qiita.com/shoheiyokoyama/items/429a7aeef5836e764bb8)に詳しく記述しましたが、`Array`や`Dictionary`など集合体を扱うクラスが準拠しているProtocolです。以下、実装したコードです。

```swift
extension CollectionType where Self.Generator.Element: Comparable {
    
    func largestValue() -> Generator.Element? {
        guard var largestValue = first else { return nil }
        
        for item in self {
            
            if item > largestValue {
                largestValue = item
            }
        }
        return largestValue
    }
}
```
`where Self.Generator.Element: Comparable`の部分で制約をかけていますね。

まず、`Collection Type`ですが、`associatedtype`で`Generator`型の定義があります。generatorは新しい要素を返す処理のことで`GeneratorType`に準拠しています。

```swift:GeneratorType
protocol GeneratorType {
    typealias Element
    func next() -> Element?
}
```
`GeneratorType`を見てみると`Element`の定義がありましたね。実際にこれが`Collection Type`の要素のGeneric型です。つまり`Collection Type`の要素の型は`Self.Generator.Element`でアクセスすることができます。もう一度制約の部分を見てみます。

```swift
where Self.Generator.Element: Comparable
```

ここでは`Self.Generator.Element`、つまり`Collection Type`の要素が`Comparable`に準拠している必要があるという制約をかけているんですね。この制約によって要素の大小を比較することができますね。

```swift
[1, 2, 3, 4, 5].largestValue()//5
"Generics".characters.largestValue()//s
(0..<1000).largestValue()//999
```

実際に`largestValue()`によって要素の中の一番大きい値が返ってきてます。



# 参考
- [The Swift Programming Language (Swift 2.2): Generics](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Generics.html)
- [【Swift】ジェネリクスが使われているメソッドを理解する](https://tech.recruit-mp.co.jp/mobile/studying-swift-generitics/)
- [Codable Tech Blog / Swift ジェネリックス(Generics)](http://blog.codable.co.jp/entry/2014/11/27/211831)
- [Objective-Cより柔軟かつ安全なプログラミングを可能にするSwiftの「ジェネリクス」](https://codezine.jp/article/detail/8449)
- [Swiftのジェネリックスについてのメモ](http://qiita.com/mini_house/items/73cefa9612d5c7680d7e)
- [Swift - Generics](http://www.tutorialspoint.com/swift/swift_generics.htm)
- [GENERIC PROTOCOLS & THEIR SHORTCOMINGS](http://krakendev.io/blog/generic-protocols-and-their-shortcomings)
- [Generics in Swift, Part 2](http://austinzheng.com/2015/09/29/swift-generics-pt-2/)
- [Swift Tutorial: Introduction to Generics](https://www.raywenderlich.com/115960/swift-tutorial-introduction-to-generics)