¿Cómo puedo extender matrices escritas en Swift?
¿Cómo puedo extender Swift Array<T>
oT[]
escribir con utilidades funcionales personalizadas?
Navegar por los documentos API de Swift muestra que los métodos Array son una extensión de T[]
, por ejemplo:
extension T[] : ArrayType {
//...
init()
var count: Int { get }
var capacity: Int { get }
var isEmpty: Bool { get }
func copy() -> T[]
}
Al copiar y pegar la misma fuente y probar variaciones como:
extension T[] : ArrayType {
func foo(){}
}
extension T[] {
func foo(){}
}
No se puede compilar con el error:
El tipo nominal
T[]
no se puede ampliar
El uso de la definición de tipo completa falla con Use of undefined type 'T'
, es decir:
extension Array<T> {
func foo(){}
}
Y también falla con Array<T : Any>
yArray<String>
.
Curiosamente Swift me permite extender una matriz sin tipo con:
extension Array {
func each(fn: (Any) -> ()) {
for i in self {
fn(i)
}
}
}
Con el que me deja llamar:
[1,2,3].each(println)
Pero no puedo crear una extensión de tipo genérica adecuada ya que el tipo parece perderse cuando fluye a través del método, por ejemplo, al intentar reemplazar el filtro integrado de Swift con :
extension Array {
func find<T>(fn: (T) -> Bool) -> T[] {
var to = T[]()
for x in self {
let t = x as T
if fn(t) {
to += t
}
}
return to
}
}
Pero el compilador lo trata como sin tipo y todavía permite llamar a la extensión con:
["A","B","C"].find { $0 > "A" }
Y cuando se avanza con un depurador, se indica que el tipo es Swift.String
, pero es un error de compilación intentar acceder a él como una cadena sin convertirlo String
primero, es decir:
["A","B","C"].find { ($0 as String).compare("A") > 0 }
¿Alguien sabe cuál es la forma correcta de crear un método de extensión escrito que actúe como las extensiones integradas?
Para ampliar matrices escritas con clases , lo siguiente me funciona (Swift 2.2 ). Por ejemplo, ordenar una matriz escrita:
class HighScoreEntry {
let score:Int
}
extension Array where Element == HighScoreEntry {
func sort() -> [HighScoreEntry] {
return sort { $0.score < $1.score }
}
}
Intentar hacer esto con una estructura o typealias dará un error:
Type 'Element' constrained to a non-protocol type 'HighScoreEntry'
Actualizar :
Para ampliar matrices escritas con clases que no sean clases, utilice el siguiente enfoque:
typealias HighScoreEntry = (Int)
extension SequenceType where Generator.Element == HighScoreEntry {
func sort() -> [HighScoreEntry] {
return sort { $0 < $1 }
}
}
En Swift 3 se ha cambiado el nombre de algunos tipos:
extension Sequence where Iterator.Element == HighScoreEntry
{
// ...
}
Después de un tiempo probando cosas diferentes, la solución parece eliminar la <T>
firma como:
extension Array {
func find(fn: (T) -> Bool) -> [T] {
var to = [T]()
for x in self {
let t = x as T;
if fn(t) {
to += t
}
}
return to
}
}
Que ahora funciona según lo previsto sin errores de compilación:
["A","B","C"].find { $0.compare("A") > 0 }
Ampliar todos los tipos:
extension Array where Element: Any {
// ...
}
Ampliar tipos comparables :
extension Array where Element: Comparable {
// ...
}
Ampliar algunos tipos:
extension Array where Element: Comparable & Hashable {
// ...
}
Extender un tipo particular :
extension Array where Element == Int {
// ...
}
Tuve un problema similar: quería extender la matriz general con un método swap(), que se suponía que debía tomar un argumento del mismo tipo que la matriz. Pero, ¿cómo se especifica el tipo genérico? Descubrí por prueba y error que lo siguiente funcionó:
extension Array {
mutating func swap(x:[Element]) {
self.removeAll()
self.appendContentsOf(x)
}
}
La clave era la palabra "Elemento". Tenga en cuenta que no definí este tipo en ninguna parte, parece existir automáticamente dentro del contexto de la extensión de la matriz y se refiere a cualquier tipo de elementos de la matriz.
No estoy 100% seguro de lo que está pasando allí, pero creo que probablemente se deba a que 'Elemento' es un tipo asociado de Matriz (consulte 'Tipos asociados' aquí https://developer.apple.com/library/ios/documentation /Swift/Conceptual/Swift_Programming_Language/Generics.html#//apple_ref/doc/uid/TP40014097-CH26-ID189 )
Sin embargo, no puedo ver ninguna referencia de esto en la referencia de la estructura de matriz ( https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_Array_Structure/index.html#//apple_ref/swift /struct/s:Sa )... así que todavía estoy un poco inseguro.