Eu quero testar a igualdade de dois valores de enumeração Swift. Por exemplo:
enum SimpleToken {
case Name(String)
case Number(Int)
}
let t1 = SimpleToken.Number(123)
let t2 = SimpleToken.Number(123)
XCTAssert(t1 == t2)
No entanto, o compilador não compila a expressão de igualdade:
error: could not find an overload for '==' that accepts the supplied arguments
XCTAssert(t1 == t2)
^~~~~~~~~~~~~~~~~~~
Eu tenho que definir minha própria sobrecarga do operador de igualdade? Eu esperava que o compilador Swift pudesse lidar com isso automaticamente, assim como Scala e Ocaml.
Equatable
eHashable
enumerações com valores associados.Respostas:
Swift 4.1+
Como o @jedwidz apontou de maneira útil, no Swift 4.1 (devido ao SE-0185 , o Swift também suporta sintetização
Equatable
eHashable
enumerações com valores associados.Portanto, se você estiver no Swift 4.1 ou mais recente, o seguinte sintetizará automaticamente os métodos necessários para que
XCTAssert(t1 == t2)
funcionem. A chave é adicionar oEquatable
protocolo à sua enumeração.Antes do Swift 4.1
Como outros observaram, Swift não sintetiza automaticamente os operadores de igualdade necessários. Deixe-me propor uma implementação mais limpa (IMHO), no entanto:
Está longe de ser o ideal - há muita repetição - mas pelo menos você não precisa fazer comutações aninhadas com instruções if dentro.
fonte
default
porcase (.Name, _): return false; case(.Number, _): return false
.case (.Name(let a), .Name(let b)) : return a == b
etc.false
? Pode ser trivial, mas esse tipo de coisa pode aumentar em certos sistemas.enum
e==
devem ser implementadas em um escopo global (fora do escopo do seu controlador de exibição).Implementar
Equatable
é um IMHO em excesso. Imagine que você tenha um enum grande e complicado com muitos casos e muitos parâmetros diferentes. Todos esses parâmetros também precisam serEquatable
implementados. Além disso, quem disse que você compara casos enum com base em tudo ou nada? E se você estiver testando valor e tiver removido apenas um parâmetro de enumeração em particular? Eu sugeriria uma abordagem simples, como:... ou no caso de avaliação de parâmetros:
Encontre uma descrição mais elaborada aqui: https://mdcdeveloper.wordpress.com/2016/12/16/unit-testing-swift-enums/
fonte
if case
eguard case
são simplesmente construções de linguagem, você pode usá-las em qualquer lugar ao testar a igualdade de enumerações nesse caso, não apenas em testes de unidade.Parece que nenhum compilador gerou operador de igualdade para enumerações nem estruturas.
Para implementar a comparação de igualdade, escreveríamos algo como:
[1] Consulte "Operadores de equivalência" em https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_43
fonte
Aqui está outra opção. É principalmente o mesmo que os outros, exceto que evita as instruções de chave aninhadas usando a
if case
sintaxe. Eu acho que isso o torna um pouco mais legível (/ suportável) e tem a vantagem de evitar o caso padrão por completo.fonte
fonte
case (.Simple(let v0), .Simple(let v1))
Também o operador pode estarstatic
dentro da enumeração. Veja minha resposta aqui.Estou usando esta solução simples no código de teste da unidade:
Ele usa interpolação de strings para realizar a comparação. Eu não o recomendaria para código de produção, mas é conciso e faz o trabalho para testes de unidade.
fonte
"\(lhs)" == "\(rhs)"
.String(describing:...)
ou o equivalente"\(...)"
. Mas isso não funciona se os valores associados diferirem :(Outra opção seria comparar as representações de string dos casos:
Por exemplo:
fonte
Outra abordagem usando
if case
vírgulas, que funciona no Swift 3:Foi assim que escrevi no meu projeto. Mas não me lembro de onde tirei a ideia. (Pesquisei no Google agora, mas não vi esse uso.) Qualquer comentário seria apreciado.
fonte
t1 e t2 não são números, são instâncias de SimpleTokens com valores associados.
Você pode dizer
Você pode então dizer
sem um erro do compilador.
Para recuperar o valor de t1, use uma instrução switch:
fonte
a 'vantagem' quando comparada à resposta aceita é que não há um caso 'padrão' na instrução de opção 'principal'; portanto, se você estender sua enumeração com outros casos, o compilador o forçará a atualizar o restante do código.
fonte
Expandindo a resposta da mbpro, veja como usei essa abordagem para verificar a igualdade de enumerações rápidas com valores associados a alguns casos extremos.
É claro que você pode fazer uma declaração de troca, mas às vezes é bom apenas verificar um valor em uma linha. Você pode fazer assim:
Se você deseja comparar duas condições na mesma cláusula if, use a vírgula em vez do
&&
operador:fonte
No Swift 4.1, basta adicionar o
Equatable
protocolo à sua enumeração e usarXCTAssert
ouXCTAssertEqual
:fonte
Você pode comparar usando o switch
fonte