Generics (泛型)

Generic codeenables you to write flexible, reusable functions and types that can work with any type, subject to requirements that you define. You can write code that avoids duplication and expresses its intent in a clear, abstracted manner.


Generics are one of the most powerful features of Swift, and much of the Swift standard library is built with generic code. In fact, you’ve been using generics throughout theLanguage Guide, even if you didn’t realize it. For example, Swift’sArrayandDictionarytypes are both generic collections. You can create an array that holdsIntvalues, or an array that holdsStringvalues, or indeed an array for any other type that can be created in Swift. Similarly, you can create a dictionary to store values of any specified type, and there are no limitations on what that type can be.

泛型是 Swift 最强大的特性之一,许多 Swift 标准库是通过泛型代码构建的。事实上,泛型的使用贯穿了整本语言手册,只是你可能没有发现而已。例如,Swift 的Array和Dictionary都是泛型集合。你可以创建一个Int数组,也可创建一个String数组,甚至可以是任意其他 Swift 类型的数组。同样的,你也可以创建存储任意指定类型的字典。

The Problem That Generics Solve (泛型所解决的问题)

Here’s a standard, non-generic function calledswapTwoInts(_:_:), which swaps twoIntvalues:


func swapTwoInts(_a:inoutInt,_b:inoutInt) {

    let temporaryA=a




This function makes use of in-out parameters to swap the values ofaandb, as described inIn-Out Parameters.


TheswapTwoInts(_:_:)function swaps the original value ofbintoa, and the original value ofaintob. You can call this function to swap the values in twoIntvariables:


var someInt=3

var anotherInt=107

swapTwoInts(&someInt, &anotherInt)

print("someInt is now\(someInt), and anotherInt is now\(anotherInt)")

// Prints "someInt is now 107, and anotherInt is now 3"

TheswapTwoInts(_:_:)function is useful, but it can only be used withIntvalues. If you want to swap twoStringvalues, or twoDoublevalues, you have to write more functions, such as theswapTwoStrings(_:_:)andswapTwoDoubles(_:_:)functions shown below:


func swapTwoStrings(_a:inoutString,_b:inoutString) {

  let temporaryA=a




func swapTwoDoubles(_a:inoutDouble,_b:inoutDouble) {

  let temporaryA=a




You may have noticed that the bodies of theswapTwoInts(_:_:),swapTwoStrings(_:_:), andswapTwoDoubles(_:_:)functions are identical. The only difference is the type of the values that they accept (Int,String, andDouble).


It would be much more useful, and considerably more flexible, to write a single function that could swap two values ofanytype. Generic code enables you to write such a function. (A generic version of these functions is defined below.)



In all three functions, it is important that the types ofaandbare defined to be the same as each other. Ifaandbwere not of the same type, it would not be possible to swap their values. Swift is a type-safe language, and does not allow (for example) a variable of typeStringand a variable of typeDoubleto swap values with each other. Attempting to do so would be reported as a compile-time error.

在上面三个函数中,a和b类型相同。如果a和b类型不同,那它们俩就不能互换值。Swift 是类型安全的语言,所以它不允许一个String类型的变量和一个Double类型的变量互换值。试图这样做将导致编译错误。

Generic Functions (泛型函数)

Generic functionscan work with any type. Here’s a generic version of theswapTwoInts(_:_:)function from above, calledswapTwoValues(_:_:):


func swapTwoValues(_a:inoutT,_b:inoutT) {

  let temporaryA=a




The body of theswapTwoValues(_:_:)function is identical to the body of theswapTwoInts(_:_:)function. However, the first line ofswapTwoValues(_:_:)is slightly different fromswapTwoInts(_:_:). Here’s how the first lines compare:


func swapTwoInts(_a:inoutInt,_b:inoutInt)

func swapTwoValues(_a:inoutT,_b:inoutT)

The generic version of the function uses aplaceholdertype name (calledT, in this case) instead of anactualtype name (such asInt,String, orDouble). The placeholder type name doesn’t say anything about whatTmust be, but itdoessay that bothaandbmust be of the same typeT, whateverTrepresents. The actual type to use in place ofTwill be determined each time theswapTwoValues(_:_:)function is called.


The other difference is that the generic function’s name (swapTwoValues(_:_:)) is followed by the placeholder type name (T) inside angle brackets (). The brackets tell Swift thatTis a placeholder type name within theswapTwoValues(_:_:)function definition. BecauseTis a placeholder, Swift does not look for an actual type calledT.

另外一个不同之处在于这个泛型函数名(swapTwoValues(_:_:))后面跟着占位类型名(T),并用尖括号括起来()。这个尖括号告诉 Swift 那个T是swapTwoValues(_:_:)函数定义内的一个占位类型名,因此 Swift 不会去查找名为T的实际类型。

TheswapTwoValues(_:_:)function can now be called in the same way asswapTwoInts, except that it can be passed two values ofanytype, as long as both of those values are of the same type as each other. Each timeswapTwoValues(_:_:)is called, the type to use forTis inferred from the types of values passed to the function.


In the two examples below,Tis inferred to beIntandStringrespectively:


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"


TheswapTwoValues(_:_:)function defined above is inspired by a generic function calledswap, which is part of the Swift standard library, and is automatically made available for you to use in your apps. If you need the behavior of theswapTwoValues(_:_:)function in your own code, you can use Swift’s existingswap(_:_:)function rather than providing your own implementation.

上面定义的swapTwoValues(_:_:)函数是受swap(_:_:)函数启发而实现的。后者存在于 Swift 标准库,你可以在你的应用程序中使用它。如果你在代码中需要类似swapTwoValues(_:_:)函数的功能,你可以使用已存在的swap(_:_:)函数。

Type Parameters (类型参数)

In theswapTwoValues(_:_:)example above, the placeholder typeTis an example of atype parameter. Type parameters specify and name a placeholder type, and are written immediately after the function’s name, between a pair of matching angle brackets (such as).


Once you specify a type parameter, you can use it to define the type of a function’s parameters (such as theaandbparameters of theswapTwoValues(_:_:)function), or as the function’s return type, or as a type annotation within the body of the function. In each case, the type parameter is replaced with anactualtype whenever the function is called. (In theswapTwoValues(_:_:)example above,Twas replaced withIntthe first time the function was called, and was replaced withStringthe second time it was called.)


You can provide more than one type parameter by writing multiple type parameter names within the angle brackets, separated by commas.


Naming Type Parameters (命名类型参数)

In most cases, type parameters have descriptive names, such asKeyandValueinDictionaryandElementinArray, which tells the reader about the relationship between the type parameter and the generic type or function it’s used in. However, when there isn’t a meaningful relationship between them, it’s traditional to name them using single letters such asT,U, andV, such asTin theswapTwoValues(_:_:)function above.



Always give type parameters upper camel case names (such asTandMyTypeParameter) to indicate that they are a placeholder for atype, not a value.


Generic Types (泛型类型)

In addition to generic functions, Swift enables you to define your owngeneric types. These are custom classes, structures, and enumerations that can work withanytype, in a similar way toArrayandDictionary.

除了泛型函数,Swift 还允许你定义泛型类型。这些自定义类、结构体和枚举可以适用于任何类型,类似于Array和Dictionary。

This section shows you how to write a generic collection type calledStack. A stack is an ordered set of values, similar to an array, but with a more restricted set of operations than Swift’sArraytype. An array allows new items to be inserted and removed at any location in the array. A stack, however, allows new items to be appended only to the end of the collection (known aspushinga new value on to the stack). Similarly, a stack allows items to be removed only from the end of the collection (known aspoppinga value off the stack).

这部分内容将向你展示如何编写一个名为Stack(栈)的泛型集合类型。栈是一系列值的有序集合,和Array类似,但它相比 Swift 的Array类型有更多的操作限制。数组允许在数组的任意位置插入新元素或是删除其中任意位置的元素。而栈只允许在集合的末端添加新的元素(称之为入)。类似的,栈也只能从末端移除元素(称之为栈)。


The concept of a stack is used by theUINavigationControllerclass to model the view controllers in its navigation hierarchy. You call theUINavigationControllerclasspushViewController(_:animated:)method to add (or push) a view controller on to the navigation stack, and itspopViewControllerAnimated(_:)method to remove (or pop) a view controller from the navigation stack. A stack is a useful collection model whenever you need a strict “last in, first out” approach to managing a collection.


The illustration below shows the push / pop behavior for a stack:


1. There are currently three values on the stack.


2. A fourth value is “pushed” on to the top of the stack.


3. The stack now holds four values, with the most recent one at the top.


4. The top item in the stack is removed, or “popped”.


5. After popping a value, the stack once again holds three values.


Here’s how to write a non-generic version of a stack, in this case for a stack ofIntvalues:


struct Int Stack{

var items= [Int]()

mutating func push(_item:Int) {



mutating func pop() ->Int{

return items.removeLast()



This structure uses anArrayproperty calleditemsto store the values in the stack.Stackprovides two methods,pushandpop, to push and pop values on and off the stack. These methods are marked asmutating, because they need to modify (ormutate) the structure’sitemsarray.


TheIntStacktype shown above can only be used withIntvalues, however. It would be much more useful to define agenericStackclass, that can manage a stack ofanytype of value.


Here’s a generic version of the same code:


struct Stack {

var items= [Element]()

mutating func push(_item:Element) {



mutating func pop() ->Element{

return items.removeLast()



Note how the generic version ofStackis essentially the same as the non-generic version, but with a type parameter calledElementinstead of an actual type ofInt. This type parameter is written within a pair of angle brackets () immediately after the structure’s name.


Elementdefines a placeholder name for “some typeElement” to be provided later on. This future type can be referred to as “Element” anywhere within the structure’s definition. In this case,Elementis used as a placeholder in three places:


1. To create a property calleditems, which is initialized with an empty array of values of typeElement


2. To specify that thepush(_:)method has a single parameter calleditem, which must be of typeElement


3. To specify that the value returned by thepop()method will be a value of typeElement


Because it is a generic type,Stackcan be used to create a stack ofanyvalid type in Swift, in a similar manner toArrayandDictionary.

由于Stack是泛型类型,因此可以用来创建 Swift 中任意有效类型的栈,就像Array和Dictionary那样。

You create a newStackinstance by writing the type to be stored in the stack within angle brackets. For example, to create a new stack of strings, you writeStack():


var stack OfStrings=Stack()





// the stack now contains 4 strings

Here’s howstackOfStringslooks after pushing these four values on to the stack:


Popping a value from the stack removes and returns the top value,"cuatro":


let fromTheTop=stackOfStrings.pop()

// fromTheTop is equal to "cuatro", and the stack now contains 3 strings

Here’s how the stack looks after popping its top value:


Extending a Generic Type (扩展一个泛型类型)

When you extend a generic type, you do not provide a type parameter list as part of the extension’s definition. Instead, the type parameter list from theoriginaltype definition is available within the body of the extension, and the original type parameter names are used to refer to the type parameters from the original definition.


The following example extends the genericStacktype to add a read-only computed property calledtopItem, which returns the top item on the stack without popping it from the stack:


extension Stack{

  var topItem:Element? {

  return items.isEmpty?nil:items[items.count-1]



ThetopItemproperty returns an optional value of typeElement. If the stack is empty,topItemreturnsnil; if the stack is not empty,topItemreturns the final item in theitemsarray.


Note that this extension does not define a type parameter list. Instead, theStacktype’s existing type parameter name,Element, is used within the extension to indicate the optional type of thetopItemcomputed property.


ThetopItemcomputed property can now be used with anyStackinstance to access and query its top item without removing it:


if let topItem=stackOfStrings.topItem{

  print("The top item on the stack is\(topItem).")


// Prints "The top item on the stack is tres."

Type Constraints (类型约束)

TheswapTwoValues(_:_:)function and theStacktype can work with any type. However, it is sometimes useful to enforce certaintype constraintson the types that can be used with generic functions and generic types. Type constraints specify that a type parameter must inherit from a specific class, or conform to a particular protocol or protocol composition.


For example, Swift’sDictionarytype places a limitation on the types that can be used as keys for a dictionary. As described inDictionaries, the type of a dictionary’s keys must behashable. That is, it must provide a way to make itself uniquely representable.Dictionaryneeds its keys to be hashable so that it can check whether it already contains a value for a particular key. Without this requirement,Dictionarycould not tell whether it should insert or replace a value for a particular key, nor would it be able to find a value for a given key that is already in the dictionary.

例如,Swift 的Dictionary类型对字典的键的类型做了些限制。在字典的描述中,字典的键的类型必须是可哈希(hashable)的。也就是说,必须有一种方法能够唯一地表示它。Dictionary的键之所以要是可哈希的,是为了便于检查字典是否已经包含某个特定键的值。若没有这个要求,Dictionary将无法判断是否可以插入或者替换某个指定键的值,也不能查找到已经存储在字典中的指定键的值。

This requirement is enforced by a type constraint on the key type forDictionary, which specifies that the key type must conform to theHashableprotocol, a special protocol defined in the Swift standard library. All of Swift’s basic types (such asString,Int,Double, andBool) are hashable by default.

为了实现这个要求,一个类型约束被强制加到Dictionary的键类型上,要求其键类型必须符合Hashable协议,这是 Swift 标准库中定义的一个特定协议。所有的 Swift 基本类型(例如String、Int、Double和Bool)默认都是可哈希的。

You can define your own type constraints when creating custom generic types, and these constraints provide much of the power of generic programming. Abstract concepts likeHashablecharacterize types in terms of their conceptual characteristics, rather than their explicit type.


Type Constraint Syntax (类型约束语法)

You write type constraints by placing a single class or protocol constraint after a type parameter’s name, separated by a colon, as part of the type parameter list. The basic syntax for type constraints on a generic function is shown below (although the syntax is the same for generic types):


func someFunction(someT:T,someU:U) {

  // function body goes here


The hypothetical function above has two type parameters. The first type parameter,T, has a type constraint that requiresTto be a subclass ofSomeClass. The second type parameter,U, has a type constraint that requiresUto conform to the protocolSomeProtocol.


Type Constraints in Action (类型约束实践)

Here’s a non-generic function calledfindIndex(ofString:in:), which is given aStringvalue to find and an array ofStringvalues within which to find it. ThefindIndex(ofString:in:)function returns an optionalIntvalue, which will be the index of the first matching string in the array if it is found, ornilif the string cannot be found:


func findIndex(ofStringvalueToFind:String,inarray: [String]) ->Int? {

for (index,value) in array.enumerated() {

  if value==valueToFind{




return nil


ThefindIndex(ofString:in:)function can be used to find a string value in an array of strings:


let strings= ["cat","dog","llama","parakeet","terrapin"]

if let foundIndex=findIndex(ofString:"llama",in:strings) {

   print("The index of llama is\(foundIndex)")


// Prints "The index of llama is 2"

The principle of finding the index of a value in an array isn’t useful only for strings, however. You can write the same functionality as a generic function by replacing any mention of strings with values of some typeTinstead.


Here’s how you might expect a generic version offindIndex(ofString:in:), calledfindIndex(of:in:), to be written. Note that the return type of this function is stillInt?, because the function returns an optional index number, not an optional value from the array. Be warned, though—this function does not compile, for reasons explained after the example:


func findIndex(ofvalueToFind:T,inarray:[T]) ->Int? {

for (index,value) in array.enumerated() {

  if value==valueToFind{

    return index



return nil


This function does not compile as written above. The problem lies with the equality check, “if value == valueToFind”. Not every type in Swift can be compared with the equal to operator (==). If you create your own class or structure to represent a complex data model, for example, then the meaning of “equal to” for that class or structure is not something that Swift can guess for you. Because of this, it is not possible to guarantee that this code will work foreverypossible typeT, and an appropriate error is reported when you try to compile the code.

上面所写的函数无法通过编译。问题出在相等性检查上,即 "if value == valueToFind"。不是所有的 Swift 类型都可以用等式符(==)进行比较。比如说,如果你创建一个自定义的类或结构体来表示一个复杂的数据模型,那么 Swift 无法猜到对于这个类或结构体而言“相等”意味着什么。正因如此,这部分代码无法保证适用于每个可能的类型T,当你试图编译这部分代码时会出现相应的错误。

All is not lost, however. The Swift standard library defines a protocol calledEquatable, which requires any conforming type to implement the equal to operator (==) and the not equal to operator (!=) to compare any two values of that type. All of Swift’s standard types automatically support theEquatableprotocol.

不过,所有的这些并不会让我们无从下手。Swift 标准库中定义了一个Equatable协议,该协议要求任何遵循该协议的类型必须实现等式符(==)及不等符(!=),从而能对该类型的任意两个值进行比较。所有的 Swift 标准类型自动支持Equatable协议。

Any type that isEquatablecan be used safely with thefindIndex(of:in:)function, because it is guaranteed to support the equal to operator. To express this fact, you write a type constraint ofEquatableas part of the type parameter’s definition when you define the function:


func findIndex(ofvalueToFind:T,inarray:[T]) ->Int? {

  for (index,value) in array.enumerated() {

    if value==valueToFind{

    return index



return nil


The single type parameter forfindIndex(of:in:)is written asT: Equatable, which means “any typeTthat conforms to theEquatableprotocol.”

findIndex(of:in:)唯一的类型参数写做T: Equatable,也就意味着“任何符合Equatable协议的类型T”。

ThefindIndex(of:in:)function now compiles successfully and can be used with any type that isEquatable, such asDoubleorString:


let double Index=findIndex(of:9.3,in: [3.14159,0.1,0.25])

// doubleIndex is an optional Int with no value, because 9.3 is not in the array

let string Index=findIndex(of:"Andrea",in: ["Mike","Malcolm","Andrea"])

// stringIndex is an optional Int containing a value of 2

Associated Types (关联类型)关联类型

When defining a protocol, it is sometimes useful to declare one or more associated types as part of the protocol’s definition. Anassociated typegives a placeholder name to a type that is used as part of the protocol. The actual type to use for that associated type is not specified until the protocol is adopted. Associated types are specified with theassociatedtypekeyword.


Associated Types in Action (关联类型实践)

Here’s an example of a protocol calledContainer, which declares an associated type calledItemType:


protocol Container{

    associated typeItemType

   mutating func append(_item:ItemType)

    var count:Int{get}

    subscript(i:Int) ->ItemType{get}


TheContainerprotocol defines three required capabilities that any container must provide:


1. It must be possible to add a new item to the container with anappend(_:)method.


2. It must be possible to access a count of the items in the container through acountproperty that returns anIntvalue.


3. It must be possible to retrieve each item in the container with a subscript that takes anIntindex value.


This protocol doesn’t specify how the items in the container should be stored or what type they are allowed to be. The protocol only specifies the three bits of functionality that any type must provide in order to be considered aContainer. A conforming type can provide additional functionality, as long as it satisfies these three requirements.


Any type that conforms to theContainerprotocol must be able to specify the type of values it stores. Specifically, it must ensure that only items of the right type are added to the container, and it must be clear about the type of the items returned by its subscript.


To define these requirements, theContainerprotocol needs a way to refer to the type of the elements that a container will hold, without knowing what that type is for a specific container. TheContainerprotocol needs to specify that any value passed to theappend(_:)method must have the same type as the container’s element type, and that the value returned by the container’s subscript will be of the same type as the container’s element type.


To achieve this, theContainerprotocol declares an associated type calledItemType, written asassociatedtype ItemType. The protocol does not define whatItemTypeis—that information is left for any conforming type to provide. Nonetheless, theItemTypealias provides a way to refer to the type of the items in aContainer, and to define a type for use with theappend(_:)method and subscript, to ensure that the expected behavior of anyContaineris enforced.

为了达到这个目的,Container协议声明了一个关联类型ItemType,写作associatedtype ItemType。这个协议无法定义ItemType是什么类型的别名,这个信息将留给遵从协议的类型来提供。尽管如此,ItemType别名提供了一种方式来引用Container中元素的类型,并将之用于append(_:)方法和下标,从而保证任何Container的行为都能够正如预期地被执行。

Here’s a version of the non-genericIntStacktype from earlier, adapted to conform to theContainerprotocol:


struct Int Stack:Container{

// original IntStack implementation

var items= [Int]()

mutating func push(_item:Int) {



mutating func pop() ->Int{

return items.removeLast()


// conformance to the Container protocol

type aliasItemType=Int

mutating func append(_item:Int) {



var count:Int{

return items.count


subscript(i:Int) ->Int{

return items[i]



TheIntStacktype implements all three of theContainerprotocol’s requirements, and in each case wraps part of theIntStacktype’s existing functionality to satisfy these requirements.


Moreover,IntStackspecifies that for this implementation ofContainer, the appropriateItemTypeto use is a type ofInt. The definition oftypealias ItemType = Intturns the abstract type ofItemTypeinto a concrete type ofIntfor this implementation of theContainerprotocol.

此外,IntStack在实现Container的要求时,指定ItemType为Int类型,即typealias ItemType = Int,从而将Container协议中抽象的ItemType类型转换为具体的Int类型。

Thanks to Swift’s type inference, you don’t actually need to declare a concreteItemTypeofIntas part of the definition ofIntStack. BecauseIntStackconforms to all of the requirements of theContainerprotocol, Swift can infer the appropriateItemTypeto use, simply by looking at the type of theappend(_:)method’sitemparameter and the return type of the subscript. Indeed, if you delete thetypealias ItemType = Intline from the code above, everything still works, because it is clear what type should be used forItemType.

由于 Swift 的类型推断,你实际上不用在IntStack的定义中声明ItemType为Int。因为IntStack符合Container协议的所有要求,Swift 只需通过append(_:)方法的item参数类型和下标返回值的类型,就可以推断出ItemType的具体类型。事实上,如果你在上面的代码中删除了typealias ItemType = Int这一行,一切仍旧可以正常工作,因为 Swift 清楚地知道ItemType应该是哪种类型。

You can also make the genericStacktype conform to theContainerprotocol:


struct Stack:Container{

// original Stack implementation

var items= [Element]()

mutating func push(_item:Element) {



mutating func pop() ->Element{

return items.removeLast()


// conformance to the Container protocol

mutating func append(_item:Element) {



var count:Int{

return items.count


subscript(i:Int) ->Element{

return items[i]



This time, the type parameterElementis used as the type of theappend(_:)method’sitemparameter and the return type of the subscript. Swift can therefore infer thatElementis the appropriate type to use as theItemTypefor this particular container.

这一次,占位类型参数Element被用作append(_:)方法的item参数和下标的返回类型。Swift 可以据此推断出Element的类型即是ItemType的类型。

Extending an Existing Type to Specify an Associated Type (通过扩展一个存在的类型来指定关联类型)

You can extend an existing type to add conformance to a protocol, as described inAdding Protocol Conformance with an Extension. This includes a protocol with an associated type.


Swift’sArraytype already provides anappend(_:)method, acountproperty, and a subscript with anIntindex to retrieve its elements. These three capabilities match the requirements of theContainerprotocol. This means that you can extendArrayto conform to theContainerprotocol simply by declaring thatArrayadopts the protocol. You do this with an empty extension, as described inDeclaring Protocol Adoption with an Extension:

Swift 的Array类型已经提供append(_:)方法,一个count属性,以及一个接受Int类型索引值的下标用以检索其元素。这三个功能都符合Container协议的要求,也就意味着你只需简单地声明Array采纳该协议就可以扩展Array,使其遵从Container协议。你可以通过一个空扩展来实现这点,正如通过扩展采纳协议中的描述:

extension Array:Container{}

Array’s existingappend(_:)method and subscript enable Swift to infer the appropriate type to use forItemType, just as for the genericStacktype above. After defining this extension, you can use anyArrayas aContainer.

如同上面的泛型Stack结构体一样,Array的append(_:)方法和下标确保了 Swift 可以推断出ItemType的类型。定义了这个扩展后,你可以将任意Array当作Container来使用。

Generic Where Clauses (泛型 Where 语句)

Type constraints, as described inType Constraints, enable you to define requirements on the type parameters associated with a generic function or type.


It can also be useful to define requirements for associated types. You do this by defining ageneric where clause. A genericwhereclause enables you to require that an associated type must conform to a certain protocol, or that certain type parameters and associated types must be the same. A genericwhereclause starts with thewherekeyword, followed by constraints for associated types or equality relationships between types and associated types. You write a genericwhereclause right before the opening curly brace of a type or function’s body.

为关联类型定义约束也是非常有用的。你可以在参数列表中通过where子句为关联类型定义约束。你能通过where子句要求一个关联类型遵从某个特定的协议,以及某个特定的类型参数和关联类型必须类型相同。你可以通过将where关键字紧跟在类型参数列表后面来定义where子句,where子句后跟一个或者多个针对关联类型的约束,以及一个或多个类型参数和关联类型间的相等关系。你可以在函数体或者类型的大括号之前添加 where 子句。

The example below defines a generic function calledallItemsMatch, which checks to see if twoContainerinstances contain the same items in the same order. The function returns a Boolean value oftrueif all items match and a value offalseif they do not.


The two containers to be checked do not have to be the same type of container (although they can be), but they do have to hold the same type of items. This requirement is expressed through a combination of type constraints and a genericwhereclause:


func allItemsMatch(_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 in0..<someContainer.count{

  if someContainer[i] !=anotherContainer[i] {

    return false



// All items match, so return true.

return true


This function takes two arguments calledsomeContainerandanotherContainer. ThesomeContainerargument is of typeC1, and theanotherContainerargument is of typeC2. BothC1andC2are type parameters for two container types to be determined when the function is called.


The following requirements are placed on the function’s two type parameters:


1. C1must conform to theContainerprotocol (written asC1: Container).

C1必须符合Container协议(写作C1: Container)。

2. C2must also conform to theContainerprotocol (written asC2: Container).

C2必须符合Container协议(写作C2: Container)。

3. TheItemTypeforC1must be the same as theItemTypeforC2(written asC1.ItemType == C2.ItemType).

C1的ItemType必须和C2的ItemType类型相同(写作C1.ItemType == C2.ItemType)。

4. TheItemTypeforC1must conform to theEquatableprotocol (written asC1.ItemType: Equatable).

C1的ItemType必须符合Equatable协议(写作C1.ItemType: Equatable)。

The first and second requirements are defined in the function’s type parameter list, and the third and fourth requirements are defined in the function’s genericwhereclause.


These requirements mean:


1. someContaineris a container of typeC1.


2. anotherContaineris a container of typeC2.


3. someContainerandanotherContainercontain the same type of items.


4. The items insomeContainercan be checked with the not equal operator (!=) to see if they are different from each other.


The third and fourth requirements combine to mean that the items inanotherContainercanalsobe checked with the!=operator, because they are exactly the same type as the items insomeContainer.


These requirements enable theallItemsMatch(_:_:)function to compare the two containers, even if they are of a different container type.


TheallItemsMatch(_:_:)function starts by checking that both containers contain the same number of items. If they contain a different number of items, there is no way that they can match, and the function returnsfalse.


After making this check, the function iterates over all of the items insomeContainerwith afor-inloop and the half-open range operator (..<). For each item, the function checks whether the item fromsomeContaineris not equal to the corresponding item inanotherContainer. If the two items are not equal, then the two containers do not match, and the function returnsfalse.


If the loop finishes without finding a mismatch, the two containers match, and the function returnstrue.


Here’s how theallItemsMatch(_:_:)function looks in action:


var stackOfStrings=Stack()




var arrayOfStrings= ["uno","dos","tres"]

if allItemsMatch(stackOfStrings,arrayOfStrings) {

  print("All items match.")

} els e{

print("Not all items match.")


// Prints "All items match."

The example above creates aStackinstance to storeStringvalues, and pushes three strings onto the stack. The example also creates anArrayinstance initialized with an array literal containing the same three strings as the stack. Even though the stack and the array are of a different type, they both conform to theContainerprotocol, and both contain the same type of values. You can therefore call theallItemsMatch(_:_:)function with these two containers as its arguments. In the example above, theallItemsMatch(_:_:)function correctly reports that all of the items in the two containers match.