Swift - Genéricos
El lenguaje Swift 4 proporciona funciones "genéricas" para escribir funciones y tipos flexibles y reutilizables. Los genéricos se utilizan para evitar la duplicación y proporcionar abstracción. Las bibliotecas estándar de Swift 4 se crean con código genérico. Los tipos Swift 4s 'Arrays' y 'Dictionary' pertenecen a colecciones genéricas. Con la ayuda de matrices y diccionarios, las matrices se definen para contener valores 'Int' y valores de 'Cadena' o cualquier otro tipo.
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)")
Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:
Before Swapping values are: 100 and 200
After Swapping values are: 200 and 100
Funciones genéricas: parámetros de tipo
Las funciones genéricas se pueden utilizar para acceder a cualquier tipo de datos como 'Int' o '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)")
Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente 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
La función exchange () se usa para intercambiar valores que se describen en el programa anterior y <T> se usa como parámetro de tipo. Por primera vez, se llama a la función exchange () para devolver valores 'Int' y la segunda llamada a la función exchange () devolverá valores 'String'. Se pueden incluir varios tipos de parámetros dentro de los corchetes angulares separados por comas.
Los parámetros de tipo se denominan definidos por el usuario para conocer el propósito del parámetro de tipo que contiene. Swift 4 proporciona <T> como nombre de parámetro de tipo genérico. Sin embargo, los parámetros de tipo como matrices y diccionarios también se pueden nombrar como clave, valor para identificar que pertenecen al tipo 'Diccionario'.
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()
Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:
[Swift 4]
[Swift 4, Generics]
[Swift 4, Generics, Type Parameters]
[Swift 4, Generics, Type Parameters, Naming Type Parameters]
Ampliación de un tipo genérico
La extensión de la propiedad de la pila para conocer la parte superior del elemento se incluye con la palabra clave 'extensión'.
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).")
}
Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente 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.
Restricciones de tipo
El lenguaje Swift 4 permite 'restricciones de tipo' para especificar si el parámetro de tipo hereda de una clase específica, o para asegurar el estándar de conformidad del 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)")
Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente 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 asociados
Swift 4 permite que los tipos asociados se declaren dentro de la definición del protocolo mediante la palabra clave '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)
Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:
[Swift 4]
[Swift 4, Generics]
[Swift 4, Generics, Type Parameters]
[Swift 4, Generics, Type Parameters, Naming Type Parameters]
Donde las cláusulas
Las restricciones de tipo permiten al usuario definir requisitos sobre los parámetros de tipo asociados con una función o tipo genérico. Para definir los requisitos para los tipos asociados, las cláusulas 'donde' se declaran como parte de la lista de parámetros de tipo. La palabra clave 'donde' se coloca inmediatamente después de la lista de parámetros de tipo seguida de restricciones de tipos asociados, relaciones de igualdad entre tipos y tipos asociados.
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)
Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:
[Swift 4]
[Swift 4, Generics]
[Swift 4, Generics, Where Clause]
[Swift 4, Generics, Where Clause]