泛型代碼可以讓你寫出根據(jù)自我需求定義、適用于任何類型的,靈活且可重用的函數(shù)和類型。它的可以讓你避免重復(fù)的代碼,用一種清晰和抽象的方式來表達代碼的意圖。
泛型是 Swift 強大特征中的其中一個,許多 Swift 標(biāo)準庫是通過泛型代碼構(gòu)建出來的。事實上,泛型的使用貫穿了整本語言手冊,只是你沒有發(fā)現(xiàn)而已。例如,Swift 的數(shù)組和字典類型都是泛型集。你可以創(chuàng)建一個Int
數(shù)組,也可創(chuàng)建一個String
數(shù)組,或者甚至于可以是任何其他 Swift 的類型數(shù)據(jù)數(shù)組。同樣的,你也可以創(chuàng)建存儲任何指定類型的字典(dictionary),而且這些類型可以是沒有限制的。
這里是一個標(biāo)準的,非泛型函數(shù)swapTwoInts
,用來交換兩個Int值:
func swapTwoInts(inout a: Int, inout b: Int) {
let temporaryA = a
a = b
b = temporaryA
}
這個函數(shù)使用寫入讀出(in-out)參數(shù)來交換a
和b
的值,請參考寫入讀出參數(shù)。
swapTwoInts
函數(shù)可以交換b
的原始值到a
,也可以交換a的原始值到b
,你可以調(diào)用這個函數(shù)交換兩個Int
變量值:
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
println("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// 輸出 "someInt is now 107, and anotherInt is now 3"
swapTwoInts
函數(shù)是非常有用的,但是它只能交換Int
值,如果你想要交換兩個String
或者Double
,就不得不寫更多的函數(shù),如 swapTwoStrings
和swapTwoDoublesfunctions
,如同如下所示:
func swapTwoStrings(inout a: String, inout b: String) {
let temporaryA = a
a = b
b = temporaryA
}
func swapTwoDoubles(inout a: Double, inout b: Double) {
let temporaryA = a
a = b
b = temporaryA
}
你可能注意到 swapTwoInts
、 swapTwoStrings
和swapTwoDoubles
函數(shù)功能都是相同的,唯一不同之處就在于傳入的變量類型不同,分別是Int
、String
和Double
。
但實際應(yīng)用中通常需要一個用處更強大并且盡可能的考慮到更多的靈活性單個函數(shù),可以用來交換兩個任何類型值,很幸運的是,泛型代碼幫你解決了這種問題。(一個這種泛型函數(shù)后面已經(jīng)定義好了。)
注意:
在所有三個函數(shù)中,a
和b
的類型是一樣的。如果a
和b
不是相同的類型,那它們倆就不能互換值。Swift 是類型安全的語言,所以它不允許一個String
類型的變量和一個Double
類型的變量互相交換值。如果一定要做,Swift 將報編譯錯誤。
泛型函數(shù)
可以工作于任何類型,這里是一個上面swapTwoInts
函數(shù)的泛型版本,用于交換兩個值:
func swapTwoValues<T>(inout a: T, inout b: T) {
let temporaryA = a
a = b
b = temporaryA
}
swapTwoValues
函數(shù)主體和swapTwoInts
函數(shù)是一樣的,它只在第一行稍微有那么一點點不同于swapTwoInts
,如下所示:
func swapTwoInts(inout a: Int, inout b: Int)
func swapTwoValues<T>(inout a: T, inout b: T)
這個函數(shù)的泛型版本使用了占位類型名字(通常此情況下用字母T
來表示)來代替實際類型名(如Int
、String
或Double
)。占位類型名沒有提示T
必須是什么類型,但是它提示了a
和b
必須是同一類型T
,而不管T
表示什么類型。只有swapTwoValues
函數(shù)在每次調(diào)用時所傳入的實際類型才能決定T
所代表的類型。
另外一個不同之處在于這個泛型函數(shù)名后面跟著的占位類型名字(T)是用尖括號括起來的(<T>
)。這個尖括號告訴 Swift 那個T
是swapTwoValues
函數(shù)所定義的一個類型。因為T
是一個占位命名類型,Swift 不會去查找命名為T的實際類型。
swapTwoValues
函數(shù)除了要求傳入的兩個任何類型值是同一類型外,也可以作為swapTwoInts
函數(shù)被調(diào)用。每次swapTwoValues
被調(diào)用,T所代表的類型值都會傳給函數(shù)。
在下面的兩個例子中,T
分別代表Int
和String
:
var someInt = 3
var anotherInt = 107
swapTwoValues(&someInt, &anotherInt)
// someInt is now 107, and anotherInt is now 3
var someString = "hello"
var anotherString = "world"
swapTwoValues(&someString, &anotherString)
// someString is now "world", and anotherString is now "hello"
注意
上面定義的函數(shù)swapTwoValues
是受swap
函數(shù)啟發(fā)而實現(xiàn)的。swap
函數(shù)存在于 Swift 標(biāo)準庫,并可以在其它類中任意使用。如果你在自己代碼中需要類似swapTwoValues
函數(shù)的功能,你可以使用已存在的交換函數(shù)swap
函數(shù)。
在上面的swapTwoValues
例子中,占位類型T
是一種類型參數(shù)的示例。類型參數(shù)指定并命名為一個占位類型,并且緊隨在函數(shù)名后面,使用一對尖括號括起來(如<T>
)。
一旦一個類型參數(shù)被指定,那么其可以被使用來定義一個函數(shù)的參數(shù)類型(如swapTwoValues
函數(shù)中的參數(shù)a
和b
),或作為一個函數(shù)返回類型,或用作函數(shù)主體中的注釋類型。在這種情況下,被類型參數(shù)所代表的占位類型不管函數(shù)任何時候被調(diào)用,都會被實際類型所替換(在上面swapTwoValues
例子中,當(dāng)函數(shù)第一次被調(diào)用時,T
被Int
替換,第二次調(diào)用時,被String
替換。)。
你可支持多個類型參數(shù),命名在尖括號中,用逗號分開。
在簡單的情況下,泛型函數(shù)或泛型類型需要指定一個占位類型(如上面的swapTwoValues
泛型函數(shù),或一個存儲單一類型的泛型集,如數(shù)組),通常用一單個字母T
來命名類型參數(shù)。不過,你可以使用任何有效的標(biāo)識符來作為類型參數(shù)名。
如果你使用多個參數(shù)定義更復(fù)雜的泛型函數(shù)或泛型類型,那么使用更多的描述類型參數(shù)是非常有用的。例如,Swift 字典(Dictionary)類型有兩個類型參數(shù),一個是鍵,另外一個是值。如果你自己寫字典,你或許會定義這兩個類型參數(shù)為KeyType
和ValueType
,用來記住它們在你的泛型代碼中的作用。
注意
請始終使用大寫字母開頭的駝峰式命名法(例如T
和KeyType
)來給類型參數(shù)命名,以表明它們是類型的占位符,而非類型值。
通常在泛型函數(shù)中,Swift 允許你定義你自己的泛型類型。這些自定義類、結(jié)構(gòu)體和枚舉作用于任何類型,如同Array
和Dictionary
的用法。
這部分向你展示如何寫一個泛型集類型--Stack
(棧)。一個棧是一系列值域的集合,和Array
(數(shù)組)類似,但其是一個比 Swift 的Array
類型更多限制的集合。一個數(shù)組可以允許其里面任何位置的插入/刪除操作,而棧,只允許在集合的末端添加新的項(如同push一個新值進棧)。同樣的一個棧也只能從末端移除項(如同pop一個值出棧)。
注意
棧的概念已被UINavigationController
類使用來模擬試圖控制器的導(dǎo)航結(jié)構(gòu)。你通過調(diào)用UINavigationController
的pushViewController:animated:
方法來為導(dǎo)航棧添加(add)新的試圖控制器;而通過popViewControllerAnimated:
的方法來從導(dǎo)航棧中移除(pop)某個試圖控制器。每當(dāng)你需要一個嚴格的后進先出
方式來管理集合,堆棧都是最實用的模型。
下圖展示了一個棧的壓棧(push)/出棧(pop)的行為:
這里展示了如何寫一個非泛型版本的棧,Int
值型的棧:
struct IntStack {
var items = Int[]()
mutating func push(item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
}
這個結(jié)構(gòu)體在棧中使用一個Array
性質(zhì)的items
存儲值。Stack
提供兩個方法:push
和pop
,從棧中壓進一個值和移除一個值。這些方法標(biāo)記為可變的,因為它們需要修改(或轉(zhuǎn)換)結(jié)構(gòu)體的items
數(shù)組。
上面所展現(xiàn)的IntStack
類型只能用于Int
值,不過,其對于定義一個泛型Stack
類(可以處理任何類型值的棧)是非常有用的。
這里是一個相同代碼的泛型版本:
struct Stack<T> {
var items = [T]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
}
注意到Stack
的泛型版本基本上和非泛型版本相同,但是泛型版本的占位類型參數(shù)為T代替了實際Int
類型。這種類型參數(shù)包含在一對尖括號里(<T>
),緊隨在結(jié)構(gòu)體名字后面。
T
定義了一個名為“某種類型T”的節(jié)點提供給后來用。這種將來類型可以在結(jié)構(gòu)體的定義里任何地方表示為“T”。在這種情況下,T
在如下三個地方被用作節(jié)點:
items
的屬性,使用空的T類型值數(shù)組對其進行初始化;item
的push
方法,該參數(shù)必須是T類型;pop
方法的返回值,該返回值將是一個T類型值。當(dāng)創(chuàng)建一個新單例并初始化時, 通過用一對緊隨在類型名后的尖括號里寫出實際指定棧用到類型,創(chuàng)建一個Stack
實例,同創(chuàng)建Array
和Dictionary
一樣:
var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
stackOfStrings.push("cuatro")
// 現(xiàn)在棧已經(jīng)有4個string了
下圖將展示stackOfStrings
如何push
這四個值進棧的過程:
從棧中pop
并移除值"cuatro":
let fromTheTop = stackOfStrings.pop()
// fromTheTop is equal to "cuatro", and the stack now contains 3 strings
下圖展示了如何從棧中pop一個值的過程:
由于Stack
是泛型類型,所以在 Swift 中其可以用來創(chuàng)建任何有效類型的棧,這種方式如同Array
和Dictionary
。
swapTwoValues
函數(shù)和Stack
類型可以作用于任何類型,不過,有的時候?qū)κ褂迷诜盒秃瘮?shù)和泛型類型上的類型強制約束為某種特定類型是非常有用的。類型約束指定了一個必須繼承自指定類的類型參數(shù),或者遵循一個特定的協(xié)議或協(xié)議構(gòu)成。
例如,Swift 的Dictionary
類型對作用于其鍵的類型做了些限制。在字典的描述中,字典的鍵類型必須是可哈希,也就是說,必須有一種方法可以使其被唯一的表示。Dictionary
之所以需要其鍵是可哈希是為了以便于其檢查其是否已經(jīng)包含某個特定鍵的值。如無此需求,Dictionary
既不會告訴是否插入或者替換了某個特定鍵的值,也不能查找到已經(jīng)存儲在字典里面的給定鍵值。
這個需求強制加上一個類型約束作用于Dictionary
的鍵上,當(dāng)然其鍵類型必須遵循Hashable
協(xié)議(Swift 標(biāo)準庫中定義的一個特定協(xié)議)。所有的 Swift 基本類型(如String
,Int
, Double
和 Bool
)默認都是可哈希。
當(dāng)你創(chuàng)建自定義泛型類型時,你可以定義你自己的類型約束,當(dāng)然,這些約束要支持泛型編程的強力特征中的多數(shù)。抽象概念如可哈希
具有的類型特征是根據(jù)它們概念特征來界定的,而不是它們的直接類型特征。
你可以寫一個在一個類型參數(shù)名后面的類型約束,通過冒號分割,來作為類型參數(shù)鏈的一部分。這種作用于泛型函數(shù)的類型約束的基礎(chǔ)語法如下所示(和泛型類型的語法相同):
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
// function body goes here
}
上面這個假定函數(shù)有兩個類型參數(shù)。第一個類型參數(shù)T
,有一個需要T
必須是SomeClass
子類的類型約束;第二個類型參數(shù)U
,有一個需要U
必須遵循SomeProtocol
協(xié)議的類型約束。
這里有個名為findStringIndex
的非泛型函數(shù),該函數(shù)功能是去查找包含一給定String
值的數(shù)組。若查找到匹配的字符串,findStringIndex
函數(shù)返回該字符串在數(shù)組中的索引值(Int
),反之則返回nil
:
func findStringIndex(array: [String], valueToFind: String) -> Int? {
for (index, value) in enumerate(array) {
if value == valueToFind {
return index
}
}
return nil
}
findStringIndex
函數(shù)可以作用于查找一字符串?dāng)?shù)組中的某個字符串:
let strings = ["cat", "dog", "llama", "parakeet", "terrapin"]
if let foundIndex = findStringIndex(strings, "llama") {
println("The index of llama is \(foundIndex)")
}
// 輸出 "The index of llama is 2"
如果只是針對字符串而言查找在數(shù)組中的某個值的索引,用處不是很大,不過,你可以寫出相同功能的泛型函數(shù)findIndex
,用某個類型T
值替換掉提到的字符串。
這里展示如何寫一個你或許期望的findStringIndex
的泛型版本findIndex
。請注意這個函數(shù)仍然返回Int
,是不是有點迷惑呢,而不是泛型類型?那是因為函數(shù)返回的是一個可選的索引數(shù),而不是從數(shù)組中得到的一個可選值。需要提醒的是,這個函數(shù)不會編譯,原因在例子后面會說明:
func findIndex<T>(array: T[], valueToFind: T) -> Int? {
for (index, value) in enumerate(array) {
if value == valueToFind {
return index
}
}
return nil
}
上面所寫的函數(shù)不會編譯。這個問題的位置在等式的檢查上,“if value == valueToFind”
。不是所有的 Swift 中的類型都可以用等式符(==)進行比較。例如,如果你創(chuàng)建一個你自己的類或結(jié)構(gòu)體來表示一個復(fù)雜的數(shù)據(jù)模型,那么 Swift 沒法猜到對于這個類或結(jié)構(gòu)體而言“等于”的意思。正因如此,這部分代碼不能可能保證工作于每個可能的類型T
,當(dāng)你試圖編譯這部分代碼時估計會出現(xiàn)相應(yīng)的錯誤。
不過,所有的這些并不會讓我們無從下手。Swift 標(biāo)準庫中定義了一個Equatable
協(xié)議,該協(xié)議要求任何遵循的類型實現(xiàn)等式符(==)和不等符(!=)對任何兩個該類型進行比較。所有的 Swift 標(biāo)準類型自動支持Equatable
協(xié)議。
任何Equatable
類型都可以安全的使用在findIndex
函數(shù)中,因為其保證支持等式操作。為了說明這個事實,當(dāng)你定義一個函數(shù)時,你可以寫一個Equatable
類型約束作為類型參數(shù)定義的一部分:
func findIndex<T: Equatable>(array: T[], valueToFind: T) -> Int? {
for (index, value) in enumerate(array) {
if value == valueToFind {
return index
}
}
return nil
}
findIndex
中這個單個類型參數(shù)寫做:T: Equatable
,也就意味著“任何T類型都遵循Equatable
協(xié)議”。
findIndex
函數(shù)現(xiàn)在則可以成功的編譯過,并且作用于任何遵循Equatable
的類型,如Double
或String
:
let doubleIndex = findIndex([3.14159, 0.1, 0.25], 9.3)
// doubleIndex is an optional Int with no value, because 9.3 is not in the array
let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea")
// stringIndex is an optional Int containing a value of 2
當(dāng)定義一個協(xié)議時,有的時候聲明一個或多個關(guān)聯(lián)類型作為協(xié)議定義的一部分是非常有用的。一個關(guān)聯(lián)類型作為協(xié)議的一部分,給定了類型的一個占位名(或別名)。作用于關(guān)聯(lián)類型上實際類型在協(xié)議被實現(xiàn)前是不需要指定的。關(guān)聯(lián)類型被指定為typealias
關(guān)鍵字。
這里是一個Container
協(xié)議的例子,定義了一個ItemType關(guān)聯(lián)類型:
protocol Container {
typealias ItemType
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
Container
協(xié)議定義了三個任何容器必須支持的兼容要求:
append
方法添加一個新item到容器里;count
屬性獲取容器里items的數(shù)量,并返回一個Int
值;Int
索引值下標(biāo)可以檢索到每一個item。這個協(xié)議沒有指定容器里item是如何存儲的或何種類型是允許的。這個協(xié)議只指定三個任何遵循Container
類型所必須支持的功能點。一個遵循的類型在滿足這三個條件的情況下也可以提供其他額外的功能。
任何遵循Container
協(xié)議的類型必須指定存儲在其里面的值類型,必須保證只有正確類型的items可以加進容器里,必須明確可以通過其下標(biāo)返回item類型。
為了定義這三個條件,Container
協(xié)議需要一個方法指定容器里的元素將會保留,而不需要知道特定容器的類型。Container
協(xié)議需要指定任何通過append
方法添加到容器里的值和容器里元素是相同類型,并且通過容器下標(biāo)返回的容器元素類型的值的類型是相同類型。
為了達到此目的,Container
協(xié)議聲明了一個ItemType的關(guān)聯(lián)類型,寫作typealias ItemType
。這個協(xié)議不會定義ItemType
是什么的別名,這個信息將由任何遵循協(xié)議的類型來提供。盡管如此,ItemType
別名提供了一種識別Container中Items類型的方法,并且用于append
方法和subscript
方法的類型定義,以便保證任何Container
期望的行為能夠被執(zhí)行。
這里是一個早前IntStack類型的非泛型版本,遵循Container協(xié)議:
struct IntStack: Container {
// IntStack的原始實現(xiàn)
var items = [Int]()
mutating func push(item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
// 遵循Container協(xié)議的實現(xiàn)
typealias ItemType = Int
mutating func append(item: Int) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Int {
return items[i]
}
}
IntStack
類型實現(xiàn)了Container
協(xié)議的所有三個要求,在IntStack
類型的每個包含部分的功能都滿足這些要求。
此外,IntStack
指定了Container
的實現(xiàn),適用的ItemType被用作Int
類型。對于這個Container
協(xié)議實現(xiàn)而言,定義 typealias ItemType = Int
,將抽象的ItemType
類型轉(zhuǎn)換為具體的Int
類型。
感謝Swift類型參考,你不用在IntStack
定義部分聲明一個具體的Int
的ItemType
。由于IntStack
遵循Container
協(xié)議的所有要求,只要通過簡單的查找append
方法的item參數(shù)類型和下標(biāo)返回的類型,Swift就可以推斷出合適的ItemType
來使用。確實,如果上面的代碼中你刪除了 typealias ItemType = Int
這一行,一切仍舊可以工作,因為它清楚的知道ItemType使用的是何種類型。
你也可以生成遵循Container
協(xié)議的泛型Stack
類型:
struct Stack<T>: Container {
// original Stack<T> implementation
var items = [T]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
// conformance to the Container protocol
mutating func append(item: T) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> T {
return items[i]
}
}
這個時候,占位類型參數(shù)T
被用作append
方法的item參數(shù)和下標(biāo)的返回類型。Swift 因此可以推斷出被用作這個特定容器的ItemType
的T
的合適類型。
在使用擴展來添加協(xié)議兼容性中有描述擴展一個存在的類型添加遵循一個協(xié)議。這個類型包含一個關(guān)聯(lián)類型的協(xié)議。
Swift的Array
已經(jīng)提供append
方法,一個count
屬性和通過下標(biāo)來查找一個自己的元素。這三個功能都達到Container
協(xié)議的要求。也就意味著你可以擴展Array
去遵循Container
協(xié)議,只要通過簡單聲明Array
適用于該協(xié)議而已。如何實踐這樣一個空擴展,在使用擴展來聲明協(xié)議的采納中有描述這樣一個實現(xiàn)一個空擴展的行為:
extension Array: Container {}
如同上面的泛型Stack
類型一樣,Array的append
方法和下標(biāo)保證Swift
可以推斷出ItemType
所使用的適用的類型。定義了這個擴展后,你可以將任何Array
當(dāng)作Container
來使用。
類型約束能夠確保類型符合泛型函數(shù)或類的定義約束。
對關(guān)聯(lián)類型定義約束是非常有用的。你可以在參數(shù)列表中通過where語句定義參數(shù)的約束。一個where
語句能夠使一個關(guān)聯(lián)類型遵循一個特定的協(xié)議,以及(或)那個特定的類型參數(shù)和關(guān)聯(lián)類型可以是相同的。你可以寫一個where
語句,緊跟在在類型參數(shù)列表后面,where語句后跟一個或者多個針對關(guān)聯(lián)類型的約束,以及(或)一個或多個類型和關(guān)聯(lián)類型間的等價(equality)關(guān)系。
下面的例子定義了一個名為allItemsMatch
的泛型函數(shù),用來檢查兩個Container
實例是否包含相同順序的相同元素。如果所有的元素能夠匹配,那么返回一個為true
的Boolean
值,反之則為false
。
被檢查的兩個Container
可以不是相同類型的容器(雖然它們可以是),但它們確實擁有相同類型的元素。這個需求通過一個類型約束和where
語句結(jié)合來表示:
func allItemsMatch<
C1: Container, C2: Container
where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
(someContainer: C1, anotherContainer: C2) -> Bool {
// 檢查兩個Container的元素個數(shù)是否相同
if someContainer.count != anotherContainer.count {
return false
}
// 檢查兩個Container相應(yīng)位置的元素彼此是否相等
for i in 0..<someContainer.count {
if someContainer[i] != anotherContainer[i] {
return false
}
}
// 如果所有元素檢查都相同則返回true
return true
}
這個函數(shù)用了兩個參數(shù):someContainer
和anotherContainer
。someContainer
參數(shù)是類型C1
,anotherContainer
參數(shù)是類型C2
。C1
和C2
是容器的兩個占位類型參數(shù),決定了這個函數(shù)何時被調(diào)用。
這個函數(shù)的類型參數(shù)列緊隨在兩個類型參數(shù)需求的后面:
C1
必須遵循Container
協(xié)議 (寫作 C1: Container
)。C2
必須遵循Container
協(xié)議 (寫作 C2: Container
)。C1
的ItemType
同樣是C2的ItemType
(寫作 C1.ItemType == C2.ItemType
)。C1
的ItemType
必須遵循Equatable
協(xié)議 (寫作 C1.ItemType: Equatable
)。第三個和第四個要求被定義為一個where
語句的一部分,寫在關(guān)鍵字where
后面,作為函數(shù)類型參數(shù)鏈的一部分。
這些要求意思是:
someContainer
是一個C1
類型的容器。anotherContainer
是一個C2
類型的容器。someContainer
和anotherContainer
包含相同的元素類型。someContainer
中的元素可以通過不等于操作(!=
)來檢查它們是否彼此不同。
第三個和第四個要求結(jié)合起來的意思是anotherContainer
中的元素也可以通過 !=
操作來檢查,因為它們在someContainer
中元素確實是相同的類型。
這些要求能夠使allItemsMatch
函數(shù)比較兩個容器,即便它們是不同的容器類型。
allItemsMatch
首先檢查兩個容器是否擁有同樣數(shù)目的items,如果它們的元素數(shù)目不同,沒有辦法進行匹配,函數(shù)就會false
。
檢查完之后,函數(shù)通過for-in
循環(huán)和半閉區(qū)間操作(..)來迭代someContainer
中的所有元素。對于每個元素,函數(shù)檢查是否someContainer
中的元素不等于對應(yīng)的anotherContainer
中的元素,如果這兩個元素不等,則這兩個容器不匹配,返回false
。
如果循環(huán)體結(jié)束后未發(fā)現(xiàn)沒有任何的不匹配,那表明兩個容器匹配,函數(shù)返回true
。
這里演示了allItemsMatch函數(shù)運算的過程:
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."
上面的例子創(chuàng)建一個Stack
單例來存儲String
,然后壓了三個字符串進棧。這個例子也創(chuàng)建了一個Array
單例,并初始化包含三個同棧里一樣的原始字符串。即便棧和數(shù)組是不同的類型,但它們都遵循Container
協(xié)議,而且它們都包含同樣的類型值。因此你可以調(diào)用allItemsMatch
函數(shù),用這兩個容器作為它的參數(shù)。在上面的例子中,allItemsMatch
函數(shù)正確的顯示了所有的這兩個容器的items
匹配。
更多建議: