Error del compilador rápido: el caso de enumeración tiene una tupla única como valor asociado, pero aquí hay varios patrones

12

Al construir un proyecto en Xcode 11.4 beta 3, obtengo este error del compilador Swift en una enumeración:

El caso de enumeración tiene una tupla única como valor asociado, pero aquí hay varios patrones, que implícitamente tuplan los patrones e intentan igualarlos.

Código fuente:

switch result {
case .error(let err):
    //
case .value(let staff, let locations):  // <-- error on this line
    //
}

Resultes una enumeración genérica con valores asociados para .errory .value. En este caso, el valor asociado es una tupla.

public enum Result<T> {
    case value(T)
    case error(Error)
}

No recuerdo haber visto este error antes, y buscarlo no arrojó ningún resultado. ¿Algunas ideas?

Eneko Alonso
fuente
1
Actualicé la pregunta, perdón por dejar eso fuera
Eneko Alonso
No hay necesidad de reinventar la rueda de resultados; Ya existe. developer.apple.com/documentation/swift/result
mate
Además, no hay Xcode 11.4 beta 4 (todavía).
mate
Lo malo, quise decir Xcode 11.4 beta 3. En lo que respecta Result, estoy de acuerdo, es el código anterior que es anterior Swift.Result. Sin embargo, eso no tiene nada que ver con el problema.
Eneko Alonso
1
Estoy completamente de acuerdo, solo estoy tratando de aclarar la pregunta. Aquí planteas un buen punto y esta es nuestra oportunidad de documentar los enfoques correctos para que otros los encuentren.
mate

Respuestas:

14

Descubrí que también puede silenciar este error tratando el valor asociado más como una tupla envolviéndolo en un conjunto adicional de corchetes:

switch result {
case .error(let err):
    //
case .value((let staff, let locations)):  
    //
}
Wernzy
fuente
1
Eso es bueno, me gusta, gracias.
Eneko Alonso
2
Sin letembargo, considere la posibilidad de moverlo si va a vincular todo: case let .value( (staff, locations) ):y case .value( let (staff, locations) ):ambos compilan. ¡Elige tu favorito!
Jessy
1
Súper menor, pero estilísticamente no estoy de acuerdo con el comentario anterior sobre vincular todo con un solo let. Tener el permiso justo a la izquierda de la cosa que está vinculada es más fácil de leer y comprender rápidamente qué cosas están vinculadas. De lo contrario, debe extrapolar mentalmente lo que el let es vinculante. Las pautas de codificación de Google para Swift también desaconsejan la entrada en cascada única: google.github.io/swift/#pattern-matching
ToddH
2
Directrices de "Google": /
Gee.E
9

Ok, lo descubrí. Parece que enumcon los valores asociados, donde el tipo de valor es una tupla, ya no se puede hacer coincidir en una declaración de cambio como esa:

// Works on Xcode 11.3.1, yields error on 11.4 (Swift 5.2)
switch result {
case .error(let err):
    //
case .value(let staff, let locations):  
    //
}

Solución

Los valores de tupple deben extraerse manualmente en Xcode 11.4 (Swift 5.2):

// Works on Xcode 11.4
switch result {
case .error(let err):
    //
case .value(let tupple):  
    let (staff, locations) = tupple
    // 
}
Eneko Alonso
fuente
Esa es ciertamente una solución.
mate
3

Este es un problema conocido: https://developer.apple.com/documentation/xcode_release_notes/xcode_11_4_release_notes

El código que se basa en el compilador automáticamente tupling un patrón puede conducir a un error del compilador al actualizar a Xcode 11.4, a pesar de que el código compilado antes. (58425942)

Por ejemplo, omitir paréntesis al encender un Opcional de un tipo de tupla provoca un error de compilación:

switch x { // error: switch must be exhaustive
case .some((let a, let b), let c): // warning: the enum case has a
     // single tuple as an associated value, but there are several
     // patterns here, implicitly tupling the patterns and trying
     // to match that instead
...

}

Solución alternativa : agregue paréntesis adicionales para tuplar explícitamente el patrón:

switch x {
case .some(((let a, let b), let c)): // Notice the extra pair of parentheses.
...

}

bolinhalouise
fuente
Gracias por la información adicional y el enlace a las notas de la versión. Me lo perdí.
Eneko Alonso
0

Si puedo, me gustaría agregar una respuesta para la if caseversión también.

if case let .value(staff, error) = result {
    // Do something
}

y luego, por supuesto, ignorando el caso:

if case let .value(staff, _) = result {
    // Do something
}
Paul Peelen
fuente