Swift Where語句
Where 語句
類型約束中描述的類型約束確保你定義關於類型參數的需求和一泛型函數或類型有關聯。
對於關聯類型的定義需求也是非常有用的。你可以通過這樣去定義where語句作爲一個類型參數隊列的一部分。一個where語句使你能夠要求一個關聯類型遵循一個特定的協議,以及(或)那個特定的類型參數和關聯類型可以是相同的。你可寫一個where語句,通過緊隨放置where關鍵字在類型參數隊列後面,其後跟着一個或者多個針對關聯類型的約束,以及(或)一個或多個類型和關聯類型的等於關係。
下面的列子定義了一個名爲allItemsMatch的泛型函數,用來檢查是否兩個Container單例包含具有相同順序的相同元素。如果匹配到所有的元素,那麼返回一個爲true的Boolean值,反之,則相反。
這兩個容器可以被檢查出是否是相同類型的容器(雖然它們可以是),但它們確實擁有相同類型的元素。這個需求通過一個類型約束和where語句結合來表示:
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
}
這個函數用了兩個參數:someContainer和anotherContainer。someContainer參數是類型C1,anotherContainer參數是類型C2。C1和C2是容器的兩個佔位類型參數,決定了這個函數何時被調用。
這個函數的類型參數列緊隨在兩個類型參數需求的後面:
-
C1必須遵循Container協議 (寫作C1: Container)。 -
C2必須遵循Container協議 (寫作C2: Container)。 -
C1的ItemType同樣是C2的ItemType(寫作C1.ItemType == C2.ItemType)。 -
C1的ItemType必須遵循Equatable協議 (寫作C1.ItemType: Equatable)。
第三個和第四個要求被定義爲一個where語句的一部分,寫在關鍵字where後面,作爲函數類型參數鏈的一部分。
這些要求意思是:
someContainer是一個C1類型的容器。 anotherContainer是一個C2類型的容器。 someContainer和anotherContainer包含相同的元素類型。 someContainer中的元素可以通過不等於操作(!=)來檢查它們是否彼此不同。
第三個和第四個要求結合起來的意思是anotherContainer中的元素也可以通過 != 操作來檢查,因爲它們在someContainer中元素確實是相同的類型。
這些要求能夠使allItemsMatch函數比較兩個容器,即便它們是不同的容器類型。
allItemsMatch首先檢查兩個容器是否擁有同樣數目的items,如果它們的元素數目不同,沒有辦法進行匹配,函數就會false。
檢查完之後,函數通過for-in循環和半閉區間操作(..)來迭代someContainer中的所有元素。對於每個元素,函數檢查是否someContainer中的元素不等於對應的anotherContainer中的元素,如果這兩個元素不等,則這兩個容器不匹配,返回false。
如果循環體結束後未發現沒有任何的不匹配,那表明兩個容器匹配,函數返回true。
這裏演示了allItemsMatch函數運算的過程:
var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
var arrayOfStrings = ["uno", "dos", "tres"]
if allItemsMatch(stackOfStrings, arrayOfStrings) {
println("All items match.")
} else {
println("Not all items match.")
}
// 輸出 "All items match."
上面的例子創建一個Stack單例來存儲String,然後壓了三個字符串進棧。這個例子也創建了一個Array單例,並初始化包含三個同棧裏一樣的原始字符串。即便棧和數組否是不同的類型,但它們都遵循Container協議,而且它們都包含同樣的類型值。你因此可以調用allItemsMatch函數,用這兩個容器作爲它的參數。在上面的例子中,allItemsMatch函數正確的顯示了所有的這兩個容器的items匹配。