Generic Swift learning

Generics allow developers to write custom functions and types that are flexible to any type of requirement. Allows us to avoid duplication of code. The intention of expressing the code in a clear and abstract way.

1 generic problem solving

The following is a non generic example
Func swapTwoIntValue (inout a:Int, inout b:Int) {/ / use the inout keyword can modify the original numerical value. Let tempValue = a a = B B} = tempValue
This function is used to exchange two numeric values
Var oneInt = 3 var = twoInt = swapTwoIntValue (&, oneInt, b:, twoInt) print (oneInt, twoInt) = //oneInt = & = twoInt = 3 =
For this example, if we want to exchange two Double types, or other types of values, we need to write a different method for each type, but the parameters of different types. In order to solve this problem, Swift provides generics to help us solve this problem.
Note: Swift is a safe language and does not allow two different types of values

2 generic functions

Here is a generic function
Func SwapTwoValues < T> (inout a: T, inout T) {tempValue = a a = b b = tempValue}
This function is similar to the example above, which is used to exchange two values of the same type, but this function uses the T placeholder instead of the actual type. No specific type is specified, but the incoming a, B must be of the same type T. When you call this function, you can specify the type of T that is specific. There is also the name of the function followed by the < T> is a function definition of a placeholder type name, and will not find the specific type of T
SwapTwoValues (& oneInt, b: & twoInt (print) oneInt:/ (oneInt), twoInt:/ (twoInt) "/ / oneInt:3, twoInt:4) var oneStr =" hello "var twoStr =" world "SwapTwoValues (& b: & oneStr, twoStr) print (oneStr:/ (oneStr), twoStr:/ (twoStr)" twoStr:hello var / / oneStr:world), oneDouble = 10.01 var twoDouble = 20.02 SwapTwoValues (& oneDouble, b: & twoDouble (print) oneDouble:/ (oneDouble), twoDouble:/ (twoDouble) "/ / oneDouble:20.02, twoDouble:10.01)
This example uses the generic perfect to solve the problems, only need to define a generic function, as long as the two parameters are the same type, do not need to write different methods according to different types of arguments.

3 type parameters

In the example above, the placeholder T is an example of a type parameter. The type parameter specifies and names a placeholder type, and uses the < > package to place the function name. Once a parameter type is determined, the parameter type can be specified, or the type of the value returned can be used as the annotation type of the function body. When the call will be replaced by the actual type, such as the transfer of Int, it is replaced by Int, if the incoming Double type is replaced by Double, etc.

4 named type parameters

The above generic example of T, is a descriptive name, usually with a single letter to name, such as: T, U, V, etc.. The T representation is just a placeholder, naming rules with the hump nomenclature

5 generic types

In addition to defining generic functions, you can also define generic types. Such as Array, Dictionary usage
The following shows a non generic version of the stack
Struct IntStack{var items = [Int] (mutating func push) / / stack (item:Int) {items} / /.Append (item) mutating (POP) func stack -> Int{return (items.removeLast)}}
This is a generic version of the stack
Struct Stack< Element> items) {var = [Element] (mutating func push (item:Element) {items.append} (item) mutating func pop (->); Element{return (items.removeLast)}}
First add &lt to the name of the function; the generic type name > < > which indicates the type parameter name. And then do the same function as a non generic stack in the function body. This generic structure is not only the value of the stack Int type, can also be other types
Var stack = Stack< String> (<) / / add following the type name; type name > stack.push ("uno") stack.push ("Dos") stack.push ("tres") stack.push ("Cuatro") (print) (stack.pop) / / Cuatro

6 extend a generic type

You can extend a generic type to add properties, methods, indexes, etc..
Extension Stack{/ / Stack to the generic extension of a computing type attribute topItem, return to the top of the item var topItem:Element? Return items.isEmpty nil {items[items.count-1]}}?: Print ("stack's top item is: / (stack.topItem!)") //stack's top item is: Tres

7 type constraint

In the above SwapTwoVlues and Stack, you can use any type. But you can also add a constraint, such as specifying a type to be used for an agreement or a specified class. In Swift (Bool, Int, Doube, String default is Hashi), the Dictionary key on the need to be able to be Hashi, easy to find whether the dictionary contains a key value.
Type constraint grammar
You can add a type or protocol name to the name of the type parameter, separated by a colon, separated by a number of types
Func somFuntion< C:SomeClass, P:SomeProtocol> (someClass:C, someProtocol:P) {}
In the definition of this function, there are two types of constraints, the first type parameter C represents a class, the second parameter P represents a protocol.

Type constraint practice

This non generic type method is used to find whether a string is in an array of characters, and there is a return of index
Func findStrInArray (array:[String], strToFind:String) -> Int? {for (index, value) in (array.enumerate) {if strToFind = = value{return index return nil}}}
The following is a generic version of the above non generic method
Func findIndex < (array:[S]; S:Equatable> -> Int valueToFind:S, _)? {for (index, value) in (array.enumerate) {if value = = valueToFind {/ / if S:Equatable did not specify this sentence would be compiled by return index return nil}}}
In the generic case, not all types can be used to compare the = = all constraints, you must specify a generic type parameter for Swift Equatable protocol, which means that the type S must be representative of the support of Equatable protocol. All Swift standard types are supported by the Equatable protocol by default
Let value = findIndex ([3.14159, 0.1, 0.25], 9.3) / / doubleIndex type Int?, its value is nil, because 9.3 is not in the array let stringIndex = findIndex ("" Mike "," Malcolm "," Andrea "," Andrea ") / / stringIndex type is Int, its value is? 2

8 association type

In the definition of the agreement, sometimes with one or more relation types as part of the definition of the agreement, as part of a type of association agreement, provides a placeholder for a type, the type will be specified in the adoption of the time. And use the keyword typealias keyword to specify the association name

Relevance type practice

The following defines a protocol that specifies an associated type
Protocol Container{typealias itemType / / declare a type of association mutating func append (item:itemType) var count:Int{get} subscript (i:Int) -> itemType {get};}
The following is a non generic version of the adoption of the Container protocol
Struct intStack: Container {/ / IntStack of the original implementation of items = [Int] (part of VaR) mutating func push (item: Int) {items.append} (item) mutating func pop (->); Int (items.removeLast) {return} / / Container protocol typealias ItemType mutating = Int func append (item: Int) {self.push (item var count: Int return)} {items.count} subscript (i: Int) -> Int return {items[i]}};
Here is a generic version of the
Struct genericStack< Element>: Container{; / / genericStack< Element> the original items = [Element] (VaR part) mutating func push (item: Element) {items.append} (item) mutating func pop (->); Element (items.removeLast) {return} / / Container protocol typealias ItemType mutating func append (item: = Element Element self.push (item)) {var} count: {return} Int items.count subscript (i: Int) -> Element return {items[i]}};

Specify an association type by extending an existing type

The consistency of the extended add protocol describes how to use an existing type to conform to a protocol, which includes the use of an association protocol
Swift in Array has met the requirements of the Container protocol, which means that the Array can be extended to adopt the Container protocol, you can achieve this by an empty extension
Extension Array: Container{}
After defining this extension, you can use Array as a Container type.

Where clause

Type constraints allow us to add some constraints and conditions for generic types. It is also necessary to add some constraints to the association type. You can use the where clause in the parameter list to add constraints to the association type.
The following example determines whether the two elements of the Container protocol are all elements of the same order and value.
Func allItemsMatch< C1:Container, C2:Container where C1.itemType (someContainer:C1 = = C2.itemType, C1.itemType:Equatable> anotherContainer:C2, _) -> Bool{if someContainer.count anotherContainer.count{return false for}! = I in 0... SomeContainer.count-1{if someContainer[i] anotherContainer[i]{return false! = return true}}}
The generic function to add a where clause in the type parameter constraints, inside C1, C2 must be adopted type Container protocol, and a generic type C1, C2 must be the same, but the generic type C1 must be adopted Equatable.
Var stackOfStrings = genericStack< String> (stackOfStrings.append) ("uno") stackOfStrings.append ("Dos") stackOfStrings.append ("tres") var arrayOfStrings = ["uno", "Dos", "tres"] type //array to meet the Container type, the above extension Array if allItemsMatch reference (stackOfStrings, arrayOfStrings) {print ("All items match.")} else {print ("Not all items match.")} / / the result is: All items match.