extension Array {
func removeObject<T where T : Equatable>(object: T) {
var index = find(self, object)
self.removeAtIndex(index)
}
}
No entanto, recebo um erro ao var index = find(self, object)
'T' não é conversível em 'T'
Eu também tentei com esta assinatura de método: func removeObject(object: AnyObject)
no entanto, recebo o mesmo erro:
'AnyObject' não é conversível em 'T'
Qual é a maneira correta de fazer isso?
T where
declaração do seu método. Tão apenasfunc removeObject<T: Equatable>
. Esta questão está relacionada: stackoverflow.com/questions/24091046/…Respostas:
A partir do Swift 2 , isso pode ser alcançado com um método de extensão de protocolo .
removeObject()
é definido como um método em todos os tipos em conformidade comRangeReplaceableCollectionType
(em particular emArray
) se os elementos da coleção foremEquatable
:Exemplo:
Atualização para o Swift 2 / Xcode 7 beta 2: Como observou a velocidade do ar nos comentários, agora é possível escrever um método em um tipo genérico mais restritivo no modelo, para que o método agora possa ser definido como uma extensão de
Array
:A extensão do protocolo ainda tem a vantagem de ser aplicável a um conjunto maior de tipos.
Atualização para o Swift 3:
fonte
remove(object: Element)
para cumprir as diretrizes de design da API Swift e evitar verbosidade. Enviei uma edição refletindo isso.Você não pode escrever um método em um tipo genérico mais restritivo no modelo.
NOTA : a partir Swift 2.0, agora você pode escrever métodos que são mais restritivas no modelo. Se você atualizou seu código para 2.0, consulte outras respostas mais abaixo para novas opções para implementar isso usando extensões.
O motivo pelo qual você obteve o erro
'T' is not convertible to 'T'
é que, na verdade, você está definindo um novo T no seu método que não está relacionado ao T. original. Se você deseja usar o T no seu método, pode fazê-lo sem especificá-lo no seu método.A razão pela qual você obtém o segundo erro
'AnyObject' is not convertible to 'T'
é que nem todos os valores possíveis para T são todas as classes. Para que uma instância seja convertida em AnyObject, ela deve ser uma classe (não pode ser uma estrutura, enumeração etc.).Sua melhor aposta é torná-la uma função que aceite a matriz como argumento:
Ou, em vez de modificar a matriz original, você pode tornar seu método mais seguro e reutilizável, retornando uma cópia:
Como uma alternativa que eu não recomendo, você pode fazer com que seu método falhe silenciosamente se o tipo armazenado na matriz não puder ser convertido no modelo de métodos (que é equivalente). (Para maior clareza, estou usando U em vez de T para o modelo do método):
Editar Para superar a falha silenciosa, você pode retornar o sucesso como um bool:
fonte
find
método?Equatable
protocolo. O UIView faz isso sim, ele irá funcionar com o UIViewsenumerate(self)
tem que consertar paraself.enumerate()
breve e concisa:
fonte
inout
. Mesmo com oinout
intacto, alguém poderia usararray = array.filter() { $0 != object }
, eu acho.Depois de ler todas as opções acima, na minha opinião a melhor resposta é:
Amostra:
Extensão da matriz Swift 2 (xcode 7b4):
Amostra:
Atualização do Swift 3.1
Voltamos a isso agora que o Swift 3.1 foi lançado. Abaixo está uma extensão que fornece variantes exaustivas, rápidas, mutantes e criadoras.
Amostras:
fonte
filter
função já lida com essa funcionalidade para você. Isso parece duplicar a funcionalidade. Mas uma boa resposta, no entanto:]]Com extensões de protocolo, você pode fazer isso,
A mesma funcionalidade para as classes,
Swift 2
Swift 3
Mas se uma classe implementa Equatable, torna-se ambígua e o compilador gera um erro.
fonte
Binary operator '===' cannot be applied to two elements of type '_' and 'Element'
Com o uso de extensões de protocolo no swift 2.0
fonte
que tal usar a filtragem? o seguinte funciona muito bem, mesmo com [AnyObject].
fonte
Há outra possibilidade de remover um item de uma matriz sem ter um uso inseguro possível, pois o tipo genérico do objeto a ser removido não pode ser o mesmo que o tipo da matriz. O uso de opcionais também não é o caminho perfeito, pois eles são muito lentos. Portanto, você pode usar um fechamento como ele já é usado ao classificar uma matriz, por exemplo.
Ao estender a
Array
classe com esta função, você pode remover elementos fazendo o seguinte:No entanto, você pode remover um elemento apenas se ele tiver o mesmo endereço de memória (apenas para classes em conformidade com o
AnyObject
protocolo, é claro):O bom é que você pode especificar o parâmetro para comparar. Por exemplo, quando você tem uma matriz de matrizes, pode especificar o fechamento de igualdade como
{ $0.count == $1.count }
e a primeira matriz com o mesmo tamanho que a remover é removida da matriz.Você pode até encurtar a chamada de função tendo a função como
mutating func removeFirst(equality: (Element) -> Bool) -> Bool
, então substitua a avaliação se porequality(item)
e chame a função por,array.removeFirst({ $0 == "Banana" })
por exemplo.fonte
==
é uma função, você também pode chamá-lo assim para qualquer tipo que implemente==
(como String, Int etc.):array.removeFirst("Banana", equality:==)
Não há necessidade de estender:
fonte
Usando em
indexOf
vez de umfor
ouenumerate
:fonte
Talvez eu não tenha entendido a pergunta.
Por que isso não funcionaria?
fonte
Finalmente acabei com o seguinte código.
fonte
Eu consegui remover a
[String:AnyObject]
de uma matriz[[String:AnyObject]]
implementando uma contagem fora de um loop for para representar o índice desde.find
e.filter
não é compatível[String:AnyObject]
.fonte
Implementação no Swift 2:
fonte
Consegui fazê-lo funcionar com:
fonte
if(index)
é inválida