1. 程式人生 > >對照Java學習Swift--泛型(Generics)

對照Java學習Swift--泛型(Generics)

簡介

泛型程式碼讓你能夠根據自定義的需求,編寫出適用於任意型別、靈活可重用的函式及型別。它能讓你避免程式碼的重複,用一種清晰和抽象的方式來表達程式碼的意圖。從Java1.5開始,引進了泛型,Swift和Java的泛型很類似,都很強大,學過Java的同學都知道。
Swift中的陣列、字典、集合都是泛型集合,同樣的Java的集合型別也是支援泛型的,可能是為了相容,也可以不指定泛型。

泛型型別

Swift 允許你定義泛型型別。這些自定義類、結構體和列舉可以適用於任何型別。
我們看下自定義棧型別的資料結構:

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

型別約束

你可以在一個型別引數名後面放置一個類名或者協議名,並用冒號進行分隔,來定義型別約束,它們將成為型別引數列表的一部分。
看個例子:

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

任何 Equatable 型別都可以安全地使用在 findIndex(::) 函式中,因為其保證支援等式操作符。在這個函式中,定義一個 Equatable 型別約束作為型別引數定義的一部分。

關聯型別

定義一個協議時,有的時候宣告一個或多個關聯型別作為協議定義的一部分將會非常有用。關聯型別為協議中的某個型別提供了一個佔位名(或者說別名),其代表的實際型別在協議被採納時才會被指定。你可以通過 associatedtype 關鍵字來指定關聯型別。
下面例子定義了一個 Container 協議,該協議定義了一個關聯型別 ItemType:

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

讓泛型 Stack 結構體遵從 Container 協議:

struct Stack<Element>: Container {
    // Stack<Element> 的原始實現部分
    var items = [Element]()
    mutating func push(item: Element) {
        items.append(item)
    }
    mutating func pop() -> Element {
        return items.removeLast()
    }
    // Container 協議的實現部分
    mutating func append(item: Element) {
        self.push(item)
    }
    var count: Int {
        return items.count
    }
    subscript(i: Int) -> Element {
        return items[i]
    }
}

這一次,佔位型別引數 Element 被用作 append(_:) 方法的 item 引數和下標的返回型別。Swift 可以據此推斷出 Element 的型別即是 ItemType 的型別。

Where 子句

型別約束讓你能夠為泛型函式或泛型型別的型別引數定義一些強制要求。
下面的例子定義了一個名為 allItemsMatch 的泛型函式,用來檢查兩個 Container 例項是否包含相同順序的相同元素。如果所有的元素能夠匹配,那麼返回 true,否則返回 false。

被檢查的兩個 Container 可以不是相同型別的容器(雖然它們可以相同),但它們必須擁有相同型別的元素。這個要求通過一個型別約束以及一個 where 子句來表示:

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
            }
        }

        // 所有元素都匹配,返回 true
        return true
}

看了這個例子很容易明白,不用多說。有Java基礎的同學,學起來應該很容易的。