Erreur du compilateur Swift: le cas enum a un tuple unique comme valeur associée, mais il existe plusieurs modèles ici

12

Construire un projet dans Xcode 11.4 beta 3, je reçois cette erreur du compilateur Swift sur une énumération:

Le cas enum a un seul tuple comme valeur associée, mais il y a plusieurs modèles ici, tupliquant implicitement les modèles et essayant de faire correspondre cela à la place

Code source:

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

Resultest une énumération générique avec des valeurs associées pour .erroret .value. Dans ce cas, la valeur associée est un tupple.

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

Je ne me souviens pas avoir vu cette erreur auparavant, et sa recherche n'a donné aucun résultat. Des idées?

Eneko Alonso
la source
1
J'ai mis à jour la question, désolé d'avoir omis cela
Eneko Alonso
Il n'est pas nécessaire de réinventer la roue des résultats; il existe déjà. developer.apple.com/documentation/swift/result
mat
De plus, il n'y a pas (encore) de Xcode 11.4 beta 4.
mat
Mon mauvais, je voulais dire Xcode 11.4 beta 3. En ce qui concerne Result, je suis d'accord, c'est l'ancien code qui est antérieur Swift.Result. Cela n'a cependant rien à voir avec le problème.
Eneko Alonso
1
Je suis complètement d'accord, j'essaie juste de nettoyer la question. Vous soulevez un bon point ici et c'est notre chance de documenter les bonnes approches à trouver.
mat

Réponses:

14

J'ai trouvé que vous pouvez également réduire cette erreur en traitant la valeur associée plus comme un tuple en l'enveloppant dans un ensemble supplémentaire de crochets:

switch result {
case .error(let err):
    //
case .value((let staff, let locations)):  
    //
}
Wernzy
la source
1
C'est bien, j'aime ça, merci.
Eneko Alonso
2
Envisagez de déplacer la letsortie si vous voulez tout lier: case let .value( (staff, locations) ):et les case .value( let (staff, locations) ):deux compilent. Choisissez votre préféré!
Jessy
1
Super mineur mais je suis en désaccord stylistique avec le commentaire ci-dessus à propos de tout lier avec un seul let. Il est plus facile de lire et de comprendre rapidement ce que les choses sont liées. Sinon, vous devez extrapoler mentalement ce que le let est contraignant. Les directives de codage de Google pour swift déconseillent également la mise en cascade unique: google.github.io/swift/#pattern-matching
ToddH
2
Consignes
9

Ok, compris. Il semble que enumles valeurs associées, où le type de valeur est un tupple, ne peuvent plus être mises en correspondance sur une instruction switch comme celle-ci:

// 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):  
    //
}

Solution

Les valeurs de tupple doivent être extraites manuellement dans 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
la source
C'est certainement une solution.
mat
3

Il s'agit d'un problème connu: https://developer.apple.com/documentation/xcode_release_notes/xcode_11_4_release_notes

Le code qui s'appuie sur le compilateur tuplant automatiquement un modèle peut entraîner une erreur de compilation lors de la mise à niveau vers Xcode 11.4, même si le code a été compilé auparavant. (58425942)

Par exemple, la suppression des parenthèses lors de l'activation d'un Facultatif d'un type de tuple provoque une erreur de compilation:

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
...

}

Solution : ajoutez des parenthèses supplémentaires pour expliciter explicitement le modèle:

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

}

bolinhalouise
la source
Merci pour les informations supplémentaires et le lien vers les notes de version. J'ai manqué ça.
Eneko Alonso
0

Si vous le permettez, j'aimerais également ajouter une réponse pour la if caseversion.

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

et puis bien sûr en ignorant la casse:

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