Swift - Genéricos

A linguagem Swift 4 fornece recursos 'genéricos' para escrever funções e tipos flexíveis e reutilizáveis. Os genéricos são usados ​​para evitar duplicação e para fornecer abstração. As bibliotecas padrão do Swift 4 são construídas com código genérico. Os tipos 'Arrays' e 'Dicionário' do Swift 4s pertencem a coleções genéricas. Com a ajuda de arrays e dicionários, os arrays são definidos para conter valores 'Int' e valores 'String' ou quaisquer outros tipos.

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

var numb1 = 100
var numb2 = 200

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

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

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

Funções genéricas: parâmetros de tipo

Funções genéricas podem ser usadas para acessar qualquer tipo de dados como 'Int' ou '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(a: &numb1, b: &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(a: &str1, b: &str2)
print("After Swapping String values are: \(str1) and \(str2)")

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

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

A função exchange () é usada para trocar valores que são descritos no programa acima e <T> é usado como um parâmetro de tipo. Pela primeira vez, a função exchange () é chamada para retornar valores 'Int' e a segunda chamada para a função exchange () retornará valores 'String'. Vários tipos de parâmetros podem ser incluídos dentro dos colchetes angulares separados por vírgulas.

Os parâmetros de tipo são nomeados como definidos pelo usuário para saber a finalidade do parâmetro de tipo que ele contém. Swift 4 fornece <T> como nome de parâmetro de tipo genérico. No entanto, parâmetros de tipo como Arrays e Dicionários também podem ser nomeados como chave, valor para identificar que eles pertencem ao tipo 'Dicionário'.

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)

let deletetos = tos.pop()

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

[Swift 4]
[Swift 4, Generics]
[Swift 4, Generics, Type Parameters]
[Swift 4, Generics, Type Parameters, Naming Type Parameters]

Estendendo um tipo genérico

Estender a propriedade stack para saber que o topo do item está incluído com a palavra-chave '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).")
}

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

["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.

Restrições de tipo

A linguagem Swift 4 permite 'restrições de tipo' para especificar se o parâmetro de tipo herda de uma classe específica ou para garantir o padrão de conformidade do protocolo.

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(a: &numb1, b: &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(a: &str1, b: &str2)
print("After Swapping String values are: \(str1) and \(str2)")

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

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

Tipos Associados

O Swift 4 permite que os tipos associados sejam declarados dentro da definição do protocolo pela palavra-chave 'associatedtype'.

protocol Container {
   associatedtype ItemType
   mutating func append(item: ItemType)
   var count: Int { get }
   subscript(i: Int) -> ItemType { get }
}
struct TOS<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: item)
   }
   var count: Int {
      return items.count
   }
   subscript(i: Int) -> T {
      return items[i]
   }
}
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)

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

[Swift 4]
[Swift 4, Generics]
[Swift 4, Generics, Type Parameters]
[Swift 4, Generics, Type Parameters, Naming Type Parameters]

Onde cláusulas

As restrições de tipo permitem que o usuário defina requisitos nos parâmetros de tipo associados a uma função ou tipo genérico. Para definir requisitos para tipos associados, as cláusulas 'where' são declaradas como parte da lista de parâmetros de tipo. A palavra-chave 'where' é colocada imediatamente após a lista de parâmetros de tipo seguidos por restrições de tipos associados, relações de igualdade entre tipos e tipos associados.

protocol Container {
   associatedtype 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: 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(item: "Swift 4")
print(tos.items)

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

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

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

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

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