Swift泛型

时间:2020-02-23 14:44:01  来源:igfitidea点击:

在本教程中,我们将讨论Swift中的泛型。
我们将看到如何扩展泛型类型,对泛型使用类型约束。

Swift泛型(Swift Generics)

泛型用于编写可在多种类型之间工作的灵活且可重用的代码。
因此,我们可以为普通类型设置通用类型,而不是为每种类型(如Int,String等)创建不同的函数/结构。
通用类型也称为占位符类型。

通常,当我们在函数中传递类型化参数时,我们会执行以下操作:

func printMe(a: Int)
{
  print(a)
}
printMe(a: 1)

func printMe(a: String)
{
  print(a)
}
printMe(a: "Anupam")

现在,我们可以轻松地使用通用参数,而不是为每种类型创建不同的函数。

为了创建一个通用函数,您需要在尖括号中的函数名称之后设置一个占位符值:<Element>。

您需要使用与参数/返回类型相同的占位符值。

您也可以传递多个占位符值。

通常,如果通用参数占位符不代表任何内容,请使用T,U,V等。

func printMe<T>(a: T)
{
  print(a)
}
printMe(a: 1)
printMe(a: "Anupam")

另一个示例:交换值的经典方式:

func swapAandB<T>(_ a: inout T, _ b: inout T) {
  let temporaryA = a
  a = b
  b = temporaryA
}
var x = "hello"
var y = "world"

swapAandB(&x, &y)
print(x)
print(y)

var x1 = 2
var y1 = 3
swapAandB(&x1, &y1)
print(x1)
print(y1)

您只能在所有T中传递相同的类型。
设置不同的类型将导致编译器错误。

我们可以通过使用两个通用参数来解决上述规则。
我们必须在函数标头本身中声明它们两者:

func printTandU<T,U>(a:T,b:U)
{
  print("T is \(a) and U is \(b)")
}

printTandU(a: 1, b: "Swift Generics")

通用类型约束

我们也可以约束泛型类型以使其符合某种类型。

class Person{

  var name:String?
  var age:Int
  
  init(name:String, age:Int)
  {
      self.name = name
      self.age = age
  }
}

func printDetails<T: Person>(a: T, b: T)
{
  print("a is \(a.name ?? "NA") and age \(a.age)")
  print("b is \(b.name ?? "NA") and age \(b.age)")
}

var p1 = Person(name: "Harry Potter",age: 11)
var p2 = Person(name: "Dumbledore",age: 700)

printDetails(a: p1, b: p2)

T符合类型Person。
因此,您不能在上述代码中传递任何不是Person类型的值。

执行以下操作会导致崩溃。

class A{
  
}
printDetails(a: A(), b: A()) //Class A isn't of the type Person.

子类将符合通用参数类型。

泛型类型必须符合协议的另一个示例:

func compareAandB<T: Equatable>(a: T, b: T)
{
  print("a == b ? \(a==b)")
}

compareAandB(a: 2, b: 3)
compareAandB(a: "Hi", b: "Hi")

如果没有Equatable协议," =="将无法正常工作。

在泛型类型上使用扩展

我们可以通过以下方式对泛型类型使用扩展:

struct Stack<T> {
  var items = [T]()
  mutating func push(_ item: T) {
      items.append(item)
  }
  mutating func pop() -> T {
      return items.removeLast()
  }
}
var stackOfInt = Stack<Int>()
stackOfInt.push(2)
stackOfInt.push(3)

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

我们不必再次在扩展名中设置通用类型。

使用where子句

我们可以使用where子句进行更严格的泛型类型约束检查。
在where子句中,我们可以添加其他条件。

protocol Hogwarts{}
protocol Muggles{}

class Person : Hogwarts{

  var name:String?
  var age:Int

  init(name:String, age:Int)
  {
      self.name = name
      self.age = age
  }
}

class M: Person, Muggles{}
func printDetails<T:Person>(a: T) where T:Muggles {
  print("a is \(a.name ?? "NA") and age \(a.age)")
}

var p1 = Person(name: "Harry Potter",age: 11)
var m2 = M(name: "Hermione",age: 700)
var p3 = Person(name: "Ron",age: 11)

printDetails(a: m2)
//printDetails(a: p1)

因此,在上面的代码中,我们添加了一个检查器,其中类型T除了符合类Person之外,还必须符合Muggles协议。

因此,在上面的代码中只需要使用M类的类型。而不是Person类。