类型约束中描述的类型约束确保你定义关于类型参数的需求和一泛型函数或类型有关联。
对于关联类型的定义需求也是非常有用的。你可以通过这样去定义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
匹配。