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]