extension - swift struct inheritance
Extensiones de matriz "donde" de Swift (1)
extension Array {
func filterWithId<T where T : Idable>(id : String) -> [T] {
...
}
}
define un método genérico filterWithId()
donde el marcador de posición genérico T
está restringido para ser Idable
. Pero esa definición introduce un marcador de posición local T
que no tiene ninguna relación con el tipo de elemento de matriz T
(y lo oculta en el alcance del método).
Por lo tanto, no ha especificado que los elementos de la matriz deben cumplir con Idable
, y esa es la razón por la que no puede llamar a self.filter() { ... }
con un cierre que espera que los elementos sean Idable
.
A partir de Swift 2 / Xcode 7 beta 2, puede definir métodos de extensión en un tipo genérico que son más restrictivos en la plantilla (compare la extensión de Array para eliminar objetos por valor para un problema muy similar):
extension Array where Element : Idable {
func filterWithId(id : String) -> [Element] {
return self.filter { (item) -> Bool in
return item.id == id
}
}
}
Alternativamente, puede definir un método de extensión de protocolo :
extension SequenceType where Generator.Element : Idable {
func filterWithId(id : String) -> [Generator.Element] {
return self.filter { (item) -> Bool in
return item.id == id
}
}
}
Luego, filterWithId()
está disponible para todos los tipos que se ajusten a SequenceType
(en particular a Array
) si el tipo de elemento de secuencia es Idable
.
En Swift 3 esto sería
extension Sequence where Iterator.Element : Idable {
func filterWithId(id : String) -> [Iterator.Element] {
return self.filter { (item) -> Bool in
return item.id == id
}
}
}
A partir de Swift 2.0 parece que podemos acercarnos más a las extensiones de tipos genéricos aplicables a situaciones predicadas.
Aunque todavía no podemos hacer esto:
protocol Idable {
var id : String { get }
}
extension Array where T : Idable {
...
}
... ahora podemos hacer esto:
extension Array {
func filterWithId<T where T : Idable>(id : String) -> [T] {
...
}
}
... y Swift lo acepta gramaticalmente. Sin embargo, por mi vida, no puedo descubrir cómo hacer feliz al compilador cuando complete los contenidos de la función de ejemplo. Supongamos que yo fuera lo más explícito posible:
extension Array {
func filterWithId<T where T : Idable>(id : String) -> [T] {
return self.filter { (item : T) -> Bool in
return item.id == id
}
}
}
... el compilador no aceptará el cierre proporcionado para filtrar, quejándose
No se puede invocar ''filtro'' con una lista de argumentos de tipo ''((T) -> Bool)''
Similar si el artículo se especifica como Idable. ¿Alguien tuvo suerte aquí?