Quiero probar la igualdad de dos valores de enumeración Swift. Por ejemplo:
enum SimpleToken {
case Name(String)
case Number(Int)
}
let t1 = SimpleToken.Number(123)
let t2 = SimpleToken.Number(123)
XCTAssert(t1 == t2)
Sin embargo, el compilador no compilará la expresión de igualdad:
error: could not find an overload for '==' that accepts the supplied arguments
XCTAssert(t1 == t2)
^~~~~~~~~~~~~~~~~~~
¿Tengo que definir mi propia sobrecarga del operador de igualdad? Esperaba que el compilador Swift lo manejara automáticamente, al igual que Scala y Ocaml.
Equatable
yHashable
para enumeraciones con valores asociados.Respuestas:
Swift 4.1+
Como @jedwidz ha señalado útilmente, desde Swift 4.1 (debido a SE-0185 , Swift también admite la síntesis
Equatable
yHashable
para enumeraciones con valores asociados.Entonces, si está utilizando Swift 4.1 o posterior, lo siguiente sintetizará automáticamente los métodos necesarios para que
XCTAssert(t1 == t2)
funcione. La clave es agregar elEquatable
protocolo a su enumeración.Antes de Swift 4.1
Como otros han señalado, Swift no sintetiza los operadores de igualdad necesarios automáticamente. Sin embargo, permítanme proponer una implementación más limpia (en mi humilde opinión):
Está lejos de ser ideal, hay mucha repetición, pero al menos no es necesario hacer cambios anidados con sentencias if dentro.
fuente
default
porcase (.Name, _): return false; case(.Number, _): return false
.case (.Name(let a), .Name(let b)) : return a == b
etc.false
? Puede ser trivial, pero ese tipo de cosas pueden sumar en ciertos sistemas.enum
y==
función debe ser implementada en un ámbito global (fuera del alcance de su vista controlador).La implementación
Equatable
es una exageración en mi humilde opinión. Imagine que tiene una enumeración complicada y grande con muchos casos y muchos parámetros diferentes. Todos estos parámetros también tendrán que haberseEquatable
implementado. Además, ¿quién dijo que compara los casos de enumeración con todo o nada? ¿Qué tal si está probando valor y ha tropezado solo con un parámetro enum particular? Sugeriría un enfoque simple, como:... o en caso de evaluación de parámetros:
Encuentre una descripción más elaborada aquí: https://mdcdeveloper.wordpress.com/2016/12/16/unit-testing-swift-enums/
fuente
if case
yguard case
son simplemente construcciones de lenguaje, puede usarlas en cualquier lugar al probar la igualdad de enumeraciones en este caso, no solo en las Pruebas unitarias.fuente
case (.Simple(let v0), .Simple(let v1))
También el operador puede estarstatic
dentro de la enumeración. Mira mi respuesta aquí.Parece que no hay un operador de igualdad generado por el compilador para las enumeraciones, ni para las estructuras.
Para implementar la comparación de igualdad, uno escribiría algo como:
[1] Consulte "Operadores de equivalencia" en https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_43
fuente
Aquí hay otra opción. Es principalmente lo mismo que los demás, excepto que evita las instrucciones de cambio anidadas mediante el uso de la
if case
sintaxis. Creo que esto lo hace un poco más legible (/ soportable) y tiene la ventaja de evitar el caso predeterminado por completo.fuente
Estoy usando esta solución simple en el código de prueba de unidad:
Utiliza la interpolación de cadenas para realizar la comparación. No lo recomendaría para el código de producción, pero es conciso y hace el trabajo para las pruebas unitarias.
fuente
"\(lhs)" == "\(rhs)"
.String(describing:...)
o el equivalente"\(...)"
. Pero esto no funciona si los valores asociados difieren :(Otra opción sería comparar las representaciones de cadena de los casos:
Por ejemplo:
fuente
Otro enfoque
if case
con comas, que funciona en Swift 3:Así es como escribí en mi proyecto. Pero no recuerdo de dónde saqué la idea. (Busqué en Google ahora pero no vi tal uso.) Cualquier comentario sería apreciado
fuente
t1 y t2 no son números, son instancias de SimpleTokens con valores asociados.
Puedes decir
Entonces puedes decir
sin un error del compilador
Para recuperar el valor de t1, use una instrucción switch:
fuente
la 'ventaja' cuando se compara con la respuesta aceptada es que no hay un caso 'predeterminado' en la declaración del interruptor 'principal', por lo que si extiende su enumeración con otros casos, el compilador lo obligará a actualizar el resto del código.
fuente
Ampliando la respuesta de mbpro, así es como utilicé ese enfoque para verificar la igualdad de enumeraciones rápidas con valores asociados con algunos casos extremos.
Por supuesto, puede hacer una declaración de cambio, pero a veces es bueno verificar solo un valor en una línea. Puedes hacerlo así:
Si desea comparar 2 condiciones en la misma cláusula if, debe usar la coma en lugar del
&&
operador:fuente
Desde Swift 4.1 simplemente agregue
Equatable
protocolo a su enumeración y useXCTAssert
oXCTAssertEqual
:fuente
Puedes comparar usando el interruptor
fuente