先來看看如果沒有 Generic Type,程式寫起來有多累人。下面範例中兩個 Function 功能相同,只是一個針對Int、一個針對String,如果將來還出現其他型別的應用,複製貼上的方式實在不夠聰明啊!
func swapTwoInts(a: Int, b: Int) -> (Int, Int) {
    return (b, a)
}
swapTwoInts(1, 2)               //return: (.0 2, .1 1)
func swapTwoStrings(a: String, b: String) -> (String, String) {
    return (b, a)
}
swapTwoStrings("foo", "bar")    //return: (.0 "bar", .1 "foo")
改成 Generic Function 不但型別通吃,更能避免複製貼上衍生的問題。
<T>宣告Generic Type用法。T。func swapTwoValues<T>(a: T, b: T) -> (T, T) {
    return (b, a)
}
swapTwoValues(1, 2)             //return: (.0 2, .1 1)
swapTwoValues(3.14, 2.71)       //return: (.0 2.71, .1 3.14)
swapTwoValues("foo", "bar")     //return: (.0 "bar", .1 "foo")
雖然 Generic 很強大,BUT! 有時候卻沒那麼神奇。下面範例試圖將compareInt()與compareString()改造成通用型的compare(),編譯器卻發出錯誤訊息。
func compareInt(a: Int, b: Int) -> Bool {
    return a > b
}
func compareString(a: String, b: String) -> Bool {
    return a > b
}
func compare<T>(a: T, b: T) -> Bool {
    return a > b    //error: error: binary operator '>' cannot be applied to two T
}
型別要能夠相互比較,必須繼承Comparable的協定。
func compare<T: Comparable>(a: T, b: T) -> Bool {
    return a > b
}
compare(1, 2)           //return: false
compare(3.14, 2.71)     //return: true
compare("foo", "bar")   //return: true
看起來只要繼承特定協定就能符合 Generic 的要求,但是下面範例編譯器又抱怨Person不支援Comparable。
func compare<T: Comparable>(a: T, b: T) -> Bool {
    return a > b
}
class Person {
    var age: Int
    init(age: Int) {
        self.age = age
    }
}
compare(Person(age: 35), Person(age: 20))   //error: error: cannot invoke 'compare' with an argument list of type '(Person, Person)'
沒有Comparable功能就來實作吧,只要補上能夠對Person做比較的運算子即可。
extension擴充Person的有關Comparable功能。==(a: Person, b: Person)。<(a: Person, b: Person)。==與<,就能延伸出其他比較運算子>、<=、>=。func compare<T: Comparable>(a: T, b: T) -> Bool {
    return a > b
}
class Person {
    var age: Int
    init(age: Int) {
        self.age = age
    }
}
extension Person: Comparable {}
func ==(a: Person, b: Person) -> Bool {
    return a.age == b.age
}
func <(a: Person, b: Person) -> Bool {
    return a.age < b.age
}
var p1 = Person(age: 10)
var p2 = Person(age: 20)
compare(p1, p2)
能夠比較Person好像沒什麼,但當我們想排序陣列,Comparable就幫上很大的忙,讓程式簡潔又邏輯清楚,是不是很神奇呢?
var numbers = [1, 3, 2, 4]
numbers.sort(<)     //return: [1, 2, 3, 4]
var persons = [Person(age: 15), Person(age: 44), Person(age: 37)]
persons.sort(<)     //return: [{age 15}, {age 37}, {age 44}]
再看一次沒有 Generic Type 的世界。
struct IntQueue {
    var items = [Int]()
    mutating func enqueue(item: Int) {
        items.append(item)
    }
    mutating func dequeue() -> Int? {
        return items.count > 0 ? items.removeAtIndex(0) : nil
    }
}
var iq = IntQueue()
iq.enqueue(1)       //return: {[1]}
iq.enqueue(2)       //return: {[1, 2]}
iq.enqueue(3)       //return: {[1, 2, 3]}
iq.dequeue()        //return: 1
iq.dequeue()        //return: 2
iq.dequeue()        //retrun: 3
iq.dequeue()        //return: nil
struct StringQueue {
    var items = [String]()
    mutating func enqueue(item: String) {
        items.append(item)
    }
    mutating func dequeue() -> String? {
        return items.count > 0 ? items.removeAtIndex(0) : nil
    }
}
var sq = StringQueue()
sq.enqueue("foo")   //return: {["foo"]}
sq.enqueue("bar")   //return: {["foo", "bar"]}
sq.enqueue("qiz")   //return: {["foo", "bar", "qiz"]}
sq.dequeue()        //return: "foo"
sq.dequeue()        //return: "bar"
sq.dequeue()        //return: "qiz"
sq.dequeue()        //return: nil
套用 Generic Type 的struct人生變成彩色的。
struct Queue<T> {
    var items = [T]()
    mutating func enqueue(item: T) {
        items.append(item)
    }
    mutating func dequeue() -> T? {
        return items.count > 0 ? items.removeAtIndex(0) : nil
    }
}
var iq = Queue<Int>()
iq.enqueue(1)       //return: {[1]}
iq.enqueue(2)       //return: {[1, 2]}
iq.enqueue(3)       //return: {[1, 2, 3]}
iq.dequeue()        //return: 1
iq.dequeue()        //return: 2
iq.dequeue()        //retrun: 3
iq.dequeue()        //return: nil
var sq = Queue<String>()
sq.enqueue("foo")   //return: {["foo"]}
sq.enqueue("bar")   //return: {["foo", "bar"]}
sq.enqueue("qiz")   //return: {["foo", "bar", "qiz"]}
sq.dequeue()        //return: "foo"
sq.dequeue()        //return: "bar"
sq.dequeue()        //return: "qiz"
sq.dequeue()        //return: nil
定義 Function 接受特定類型的物件,並可搭配where額外限目標制物件必須符合哪些protocol。
eat<T: Stuff where T: Eatable>(food: T)要求食物要是個東西Stuff,不管好吃Delicious或難吃Disgusting只要能吃Eatable就可以。Stone沒有繼承Eatable,呼叫eat()會發現東西啃不下去。
protocol Eatable {}
protocol Delicious {}
protocol Disgusting {}
class Stuff {}
class Stone: Stuff {}
class Food: Stuff, Eatable {}
class DeliciousFood: Food, Delicious {}
class DisgustingFood: Food, Disgusting {}
func eat<T: Stuff where T: Eatable>(food: T) {}
eat(Food())
eat(DeliciousFood())
eat(DisgustingFood())
eat(Stone())    //error: cannot invoke 'eat' with an argument list of type '(Stone)'
Generic Class 實作方式與 Struct 大同小異,就差在繼承機制而已。
下面範例,雖然ColorBall繼承與實作了Colorful協定,但因為Queue<T: Box where T: Colorful>只接受Box物件,所以ColorBall就被擋在門口囉。
protocol Colorful {
    var color: String { get }
}
class Box {}
class ColorBox: Box, Colorful {
    var color: String
    init(color: String) {
        self.color = color
    }
}
class Ball {}
class ColorBall: Ball, Colorful {
    var color: String
    init(color: String) {
        self.color = color
    }
}
struct Queue<T: Box where T: Colorful> {
    var items = [T]()
    mutating func enqueue(item: T) {
        items.append(item)
    }
    mutating func dequeue() -> T? {
        return items.count > 0 ? items.removeAtIndex(0) : nil
    }
    func countColorItems(color: String) -> Int {
        return items.reduce(0) { $1.color == color ? $0 + 1 : $0 }
    }
}
var queue = Queue<ColorBox>()
queue.enqueue(ColorBox(color: "red"))
queue.enqueue(ColorBox(color: "blue"))
queue.enqueue(ColorBox(color: "red"))
queue.enqueue(ColorBox(color: "blue"))
queue.countColorItems("red")  //return: 2
queue.enqueue(ColorBall(color: "yellow"))   // error: cannot invoke 'enqueue' with an argument list of type '(ColorBall)'
reduce()神奇用法請參考連結。