Swift - 泛型



Swift 提供了一个称为“泛型”的特殊功能,用于编写灵活且可重用的函数和类型,这些函数和类型可以很好地与任何其他类型一起使用。泛型用于避免重复和提供抽象。Swift 有一些使用泛型代码构建的标准库。数组和字典类型属于泛型集合。

因此,我们可以创建一个保存字符串值的数组,也可以创建一个保存整数值的数组。字典也是如此。

示例

func exchange(inout a: Int, inout b: Int) {
   let temp = a
   a = b
   b = temp
}

var numb1 = 100
var numb2 = 200

print("Before Swapping values are: \(numb1) and \(numb2)")
exchange(&numb1, &numb2)
print("After Swapping values are: \(numb1) and \(numb2)")

输出

它将产生以下输出:

Before Swapping values are: 100 and 200
After Swapping values are: 200 and 100

泛型函数

泛型函数是可以用于访问任何数据类型(如“Int”或“String”)同时保持类型安全的特殊函数。或者我们可以说泛型函数可以在不指定声明时实际类型的情况下与不同类型一起工作。

示例

在下面的示例中,函数 exchange() 用于交换上述程序中描述的值,而 <T> 用作类型参数。第一次调用函数 exchange() 以返回“Int”值,第二次调用函数 exchange() 将返回“String”值。可以在尖括号内用逗号分隔多个参数类型。

func exchange<T>(_ a: inout T, _ b: inout T) {
   let temp = a
   a = b
   b = temp
}

var numb1 = 100
var numb2 = 200

print("Before Swapping Int values are: \(numb1) and \(numb2)")
exchange(&numb1, &numb2)
print("After Swapping Int values are: \(numb1) and \(numb2)")

var str1 = "Generics"
var str2 = "Functions"

print("Before Swapping String values are: \(str1) and \(str2)")
exchange(&str1, &str2)
print("After Swapping String values are: \(str1) and \(str2)")

输出

它将产生以下输出:

Before Swapping Int values are: 100 and 200
After Swapping Int values are: 200 and 100
Before Swapping String values are: Generics and Functions
After Swapping String values are: Functions and Generics

类型参数

类型参数被命名为用户定义的,以便了解它保存的类型参数的目的。Swift 提供 <T> 作为泛型类型参数名称。但是,像数组和字典这样的类型参数也可以命名为键、值,以识别它们属于“字典”类型。我们可以通过在尖括号内编写多个类型参数名称来提供多个类型参数,其中每个名称都用逗号分隔。

示例

// Generic Types
struct TOS<T> {
   var items = [T]()
    
   mutating func push(item: T) {
      items.append(item)
   }
    
   mutating func pop() -> T? {
      return items.popLast()
   }
}

var tos = TOS<String>()
tos.push(item: "Swift 4")
print(tos.items)

tos.push(item: "Generics")
print(tos.items)

tos.push(item: "Type Parameters")
print(tos.items)

tos.push(item: "Naming Type Parameters")
print(tos.items)

if let deletetos = tos.pop() {
   print("Popped item: \(deletetos)")
} else {
   print("The stack is empty.")
}
输出

它将产生以下输出:

["Swift 4"]
["Swift 4", "Generics"]
["Swift 4", "Generics", "Type Parameters"]
["Swift 4", "Generics", "Type Parameters", "Naming Type Parameters"]
Popped item: Naming Type Parameters

泛型类型和扩展泛型类型

在 Swift 中,我们可以定义泛型类型来创建灵活且可重用的结构、类或枚举,这些结构、类或枚举可以轻松地与任何数据类型一起使用。此外,我们可以使用 extension 关键字扩展泛型类型的功能。

示例

struct TOS<T> {
   var items = [T]()
   mutating func push(item: T) {
      items.append(item)
   }

   mutating func pop() -> T {
      return items.removeLast()
   }
}

var tos = TOS<String>()
tos.push(item: "Swift 4")
print(tos.items)

tos.push(item: "Generics")
print(tos.items)

tos.push(item: "Type Parameters")
print(tos.items)

tos.push(item: "Naming Type Parameters")
print(tos.items)

extension TOS {
   var first: T? {
      return items.isEmpty ? nil : items[items.count - 1]
   }
}

if let first = tos.first {
   print("The top item on the stack is \(first).")
}

输出

它将产生以下输出:

["Swift 4"]
["Swift 4", "Generics"]
["Swift 4", "Generics", "Type Parameters"]
["Swift 4", "Generics", "Type Parameters", "Naming Type Parameters"]
The top item on the stack is Naming Type Parameters.

类型约束

Swift 允许“类型约束”来指定类型参数是否继承自特定类,或确保协议一致性标准。我们可以将它们与类和协议一起使用以指定更复杂的约束。在创建自定义泛型类型时,我们可以创建自己的类型约束。

语法

以下是类型约束的语法:

Func functionName<T: className, U: protocolName>(variable1: T, variable2: U){
   // Function body
}

示例

// A generic function with a type constraint
func show<T: CustomStringConvertible>(item: T) {
   print(item.description)
}

let str = "Welcome Swift"
let number = 22

show(item: str) 
show(item: number)    

输出

它将产生以下输出:

Welcome Swift
22

Where 子句

类型约束使用户能够定义与泛型函数或类型关联的类型参数的要求。为了定义关联类型的要求,'where' 子句被声明为类型参数列表的一部分。'where' 关键字紧跟在类型参数列表之后,然后是关联类型的约束,以及类型和关联类型之间的相等关系。

示例

protocol Container {
   typealias ItemType
   mutating func append(item: ItemType)
   var count: Int { get }
   subscript(i: Int) -> ItemType { get }
}

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]
   }
}

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
}

var tos = Stack<String>()
tos.push("Swift 4")
print(tos.items)

tos.push("Generics")
print(tos.items)

tos.push("Where Clause")
print(tos.items)

var eos = ["Swift 4", "Generics", "Where Clause"]
print(eos)

输出

它将产生以下输出:

[Swift 4]
[Swift 4, Generics]
[Swift 4, Generics, Where Clause]
[Swift 4, Generics, Where Clause]
广告