Resolve the support and use of generics in Swift

  • 2020-05-17 06:37:47
  • OfStack

1. Functions that take a generic type as a parameter

Generics are the powerful core of the Swift language. Generics are an abstraction of types that allow developers to express the intent of their code in a more flexible and convenient way. We know, there is reference function parameters must have a clear argument types, some developers will meet this kind of circumstance, write a function is used to exchange of two variables, because there are types of variables, to achieve the same function, may need to override into multiple function to realize, this greatly wasted development costs, use generics, can perfect solve this problem, the example code is as follows:


func exchange<T>(inout param1:T,inout param2:T){
  let tmp = param1
  param1 = param2
  param2 = tmp
}
var p1 = "15"
var p2 = "40"
exchange(&p1, param2: &p2)

The above method allows you to swap variables of any of the same type, using generics in function arguments, after the function name < > Parameter placeholders are defined in. If there are multiple parameter placeholders, separate them by a comma.

2. Application of generics in types

Generics can be used as parameters and return values of functions. Besides, when defining types, flexible application of generics can also solve many thorny problems, such as implementing a collection type with a stack structure. The sample code is as follows:


struct Stack<ItemType> {
  var items:[ItemType] = []
  mutating func push(param:ItemType) {
    self.items.append(param)
  }
  mutating func pop()->ItemType{
    return self.items.removeLast()
  }
}
// The integer stack 
var obj1 = Stack<Int>()
obj1.push(1)
obj1.pop()
// A string of stack 
var obj2 = Stack<String>()
obj2.push("HS")
obj2.pop()

You do not need to use it when extending a type that USES generics < > Generics can be defined by directly using the generic placeholder of the original definition, as shown in the following example:


extension Stack{
  func getArray() -> [ItemType] {
    return items
  }
}

Sometimes, developers need to impose some constraints on generics, such as only allowing the generics to be inherited from a class or to implement a protocol. The sample code is as follows:


class MyClass {
  
}
// only MyClass Can be subclassed Stack The creation of a stack 
struct Stack<ItemType:MyClass> {
  var items:[ItemType] = []
  mutating func push(param:ItemType) {
    self.items.append(param)
  }
  mutating func pop()->ItemType{
    return self.items.removeLast()
  }
}

In the protocol, you can use another way to do generic programming, using the associatedtype keyword for type association, as shown below:


protocol MyProtocol {
  // The type is specified when the protocol is implemented 
  associatedtype ItemType
  var param:ItemType {get set}
}
class MyClass:MyProtocol {
  // Due to the Swift Can automatically identify the type   This is a MyProtocol In the ItemType for Int
  var param: Int = 0
}

3. The combination of generics and where clauses

The use of the where clause makes it possible to impose tighter constraints on generics to suit the logic required by the developer, as shown below:


//T and C You have to follow the integer protocol 
class MyClassTwo<T,C where T:IntegerType,C:IntegerType> {
  var param1:T
  var param2:C
  init(param1:T,param2:C){
    self.param1=param1
    self.param2=param2
    
  }
}

var obj3 = MyClassTwo(param1: 1, param2: 1)


Related articles: