extension Array {
func removeObject<T where T : Equatable>(object: T) {
var index = find(self, object)
self.removeAtIndex(index)
}
}
Sin embargo, aparece un error en var index = find(self, object)
'T' no es convertible a 'T'
También probé con la firma de este método: func removeObject(object: AnyObject)
sin embargo, obtengo el mismo error:
'AnyObject' no es convertible a 'T'
¿Cuál es la forma apropiada de hacer esto?
T where
de su declaración de método. Por lo que sólofunc removeObject<T: Equatable>
. Esta pregunta está relacionada: stackoverflow.com/questions/24091046/…Respuestas:
A partir de Swift 2 , esto se puede lograr con un método de extensión de protocolo .
removeObject()
se define como un método en todos los tipos que se ajustanRangeReplaceableCollectionType
(en particular aArray
) si los elementos de la colección sonEquatable
:Ejemplo:
Actualización para Swift 2 / Xcode 7 beta 2: como Airspeed Velocity notó en los comentarios, ahora es posible escribir un método en un tipo genérico que sea más restrictivo en la plantilla, por lo que el método ahora podría definirse como una extensión de
Array
:La extensión de protocolo todavía tiene la ventaja de ser aplicable a un conjunto de tipos más grande.
Actualización para Swift 3:
fuente
remove(object: Element)
para cumplir con las pautas de diseño de la API Swift y evitar la verbosidad. He enviado una edición que refleja esto.No puede escribir un método en un tipo genérico que sea más restrictivo en la plantilla.
NOTA : a partir de Swift 2.0, ahora puede escribir métodos que son más restrictivos en la plantilla. Si ha actualizado su código a 2.0, vea otras respuestas más abajo para conocer nuevas opciones para implementar esto usando extensiones.
La razón por la que obtiene el error
'T' is not convertible to 'T'
es que en realidad está definiendo un nuevo T en su método que no está relacionada en absoluto con la T. original. Si desea utilizar T en su método, puede hacerlo sin especificarlo en su método.La razón por la que obtiene el segundo error
'AnyObject' is not convertible to 'T'
es que todos los valores posibles para T no son todas las clases. Para que una instancia se convierta a AnyObject, debe ser una clase (no puede ser una estructura, enumeración, etc.).Su mejor opción es hacer que sea una función que acepte la matriz como argumento:
O, en lugar de modificar la matriz original, puede hacer que su método sea más seguro y reutilizable devolviendo una copia:
Como alternativa que no recomiendo, puede hacer que su método falle silenciosamente si el tipo almacenado en la matriz no se puede convertir a la plantilla de métodos (eso es equiparable). (Para mayor claridad, estoy usando U en lugar de T para la plantilla del método):
Editar Para superar la falla silenciosa, puede devolver el éxito como un bool:
fuente
find
método?Equatable
protocolo. UIView lo hace, sí, funcionará con UIViewsenumerate(self)
tengo que arreglarloself.enumerate()
breve y concisamente:
fuente
inout
, también. Incluso con loinout
intacto, uno podría usar,array = array.filter() { $0 != object }
creo.Después de leer todo lo anterior, en mi opinión, la mejor respuesta es:
Muestra:
Extensión de matriz Swift 2 (xcode 7b4):
Muestra:
Actualización Swift 3.1
Volví a esto ahora que Swift 3.1 está fuera. A continuación se muestra una extensión que proporciona variantes exhaustivas, rápidas, mutantes y creadoras.
Muestras:
fuente
filter
función ya maneja esa funcionalidad por usted. Esto parece duplicar la funcionalidad. Pero una buena respuesta, no obstante:]Con las extensiones de protocolo puedes hacer esto,
Misma funcionalidad para las clases,
Swift 2
Swift 3
Pero si una clase implementa Equatable se vuelve ambigua y el compilador da un error de lanzamiento.
fuente
Binary operator '===' cannot be applied to two elements of type '_' and 'Element'
Con el uso de extensiones de protocolo en swift 2.0
fuente
¿Qué hay de usar el filtrado? lo siguiente funciona bastante bien incluso con [AnyObject].
fuente
Existe otra posibilidad de eliminar un elemento de una matriz sin tener un posible uso inseguro, ya que el tipo genérico del objeto a eliminar no puede ser el mismo que el tipo de la matriz. El uso de opcionales tampoco es la manera perfecta de hacerlo, ya que son muy lentos. Por lo tanto, podría usar un cierre como ya se usa al ordenar una matriz, por ejemplo.
Cuando extiende la
Array
clase con esta función, puede eliminar elementos haciendo lo siguiente:Sin embargo, incluso podría eliminar un elemento solo si tiene la misma dirección de memoria (solo para las clases que se ajustan al
AnyObject
protocolo, por supuesto):Lo bueno es que puede especificar el parámetro para comparar. Por ejemplo, cuando tiene una matriz de matrices, puede especificar el cierre de igualdad como
{ $0.count == $1.count }
y la primera matriz que tiene el mismo tamaño que la que se elimina se elimina de la matriz.Incluso podría acortar la llamada a la función teniendo la función como
mutating func removeFirst(equality: (Element) -> Bool) -> Bool
, luego reemplazar la evaluación if conequality(item)
y llamar a la función por,array.removeFirst({ $0 == "Banana" })
por ejemplo.fuente
==
es una función, también puede llamarlo así para cualquier tipo que implemente==
(como String, Int, etc.):array.removeFirst("Banana", equality:==)
No es necesario extender:
fuente
Usando en
indexOf
lugar de afor
oenumerate
:fuente
Quizás no entendí la pregunta.
¿Por qué no funcionaría esto?
fuente
Finalmente terminé con el siguiente código.
fuente
Logré eliminar a
[String:AnyObject]
de una matriz[[String:AnyObject]]
implementando un conteo fuera de un bucle for para representar el índice desde entonces.find
y.filter
no son compatibles con[String:AnyObject]
.fuente
Implementación en Swift 2:
fuente
Pude hacerlo funcionar con:
fuente
if(index)
no es válida