Swift Compiler Error: Der Enum-Fall hat ein einzelnes Tupel als zugeordneten Wert, aber hier gibt es mehrere Muster

12

Beim Erstellen eines Projekts in Xcode 11.4 Beta 3 wird dieser Swift Compiler-Fehler in einer Aufzählung angezeigt:

Der Enum-Fall hat ein einzelnes Tupel als zugeordneten Wert, aber hier gibt es mehrere Muster, die implizit die Muster tupeln und stattdessen versuchen, diese abzugleichen

Quellcode:

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

Resultist eine generische Aufzählung mit zugehörigen Werten für .errorund .value. In diesem Fall ist der zugehörige Wert ein Tupple.

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

Erinnern Sie sich nicht, diesen Fehler zuvor gesehen zu haben, und die Suche danach ergab keine Ergebnisse. Irgendwelche Ideen?

Eneko Alonso
quelle
1
Ich habe die Frage aktualisiert, sorry, dass ich das
weggelassen habe
Das Ergebnisrad muss nicht neu erfunden werden. es existiert bereits. developer.apple.com/documentation/swift/result
matt
Außerdem gibt es (noch) keinen Xcode 11.4 Beta 4.
Matt
Mein schlechtes, ich meinte Xcode 11.4 Beta 3. In Bezug auf Result, ich stimme zu, ist es alter Code, der älter ist als Swift.Result. Das hat aber nichts mit dem Thema zu tun.
Eneko Alonso
1
Ich stimme vollkommen zu, ich versuche nur, die Frage zu klären. Sie sprechen hier einen guten Punkt an und dies ist unsere Chance, die richtigen Ansätze zu dokumentieren, die andere finden können.
Matt

Antworten:

14

Ich habe festgestellt, dass Sie diesen Fehler auch zum Schweigen bringen können, indem Sie den zugehörigen Wert eher wie ein Tupel behandeln, indem Sie ihn in zusätzliche Klammern setzen:

switch result {
case .error(let err):
    //
case .value((let staff, let locations)):  
    //
}
Wernzy
quelle
1
Das ist schön, ich mag es, danke.
Eneko Alonso
2
Ziehen letSie in Betracht, das Out zu verschieben, wenn Sie alles binden möchten: case let .value( (staff, locations) ):und case .value( let (staff, locations) ):beide kompilieren. Wählen Sie Ihren Favoriten!
Jessy
1
Super minor, aber ich stimme dem obigen Kommentar über das Binden von allem mit einer einzigen Vermietung stilistisch nicht zu. Es ist einfacher zu lesen und schnell zu verstehen, welche Dinge gebunden sind, wenn Sie das Zeichen links neben dem gebundenen Objekt haben. Andernfalls müssen Sie mental extrapolieren, was die Vermietung bindend ist. Die Codierungsrichtlinien von Google für Swift raten auch von der einzelnen Kaskadierung ab: google.github.io/swift/#pattern-matching
ToddH
2
"Googles" Richtlinien: /
Gee.E
9

Ok, habe es herausgefunden. Scheint so, als ob enummit zugeordneten Werten, bei denen der Werttyp ein Tupple ist, eine switch-Anweisung wie diese nicht mehr abgeglichen werden kann:

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

Lösung

Werte aus tupple müssen in Xcode 11.4 (Swift 5.2) manuell extrahiert werden:

// Works on Xcode 11.4
switch result {
case .error(let err):
    //
case .value(let tupple):  
    let (staff, locations) = tupple
    // 
}
Eneko Alonso
quelle
Das ist sicherlich eine Lösung.
Matt
3

Dies ist ein bekanntes Problem: https://developer.apple.com/documentation/xcode_release_notes/xcode_11_4_release_notes

Code, bei dem der Compiler ein Muster automatisch tupft, kann beim Upgrade auf Xcode 11.4 zu einem Compilerfehler führen, obwohl der Code zuvor kompiliert wurde. (58425942)

Das Auslassen von Klammern beim Einschalten eines optionalen Tupeltyps führt beispielsweise zu einem Compilerfehler:

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

}}

Problemumgehung : Fügen Sie zusätzliche Klammern hinzu, um das Muster explizit zu tupeln :

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

}}

bolinhalouise
quelle
Vielen Dank für die zusätzlichen Informationen und den Link zu den Versionshinweisen. Das habe ich vermisst.
Eneko Alonso
0

Wenn ich darf, möchte ich auch eine Antwort für die if caseVersion hinzufügen .

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

und dann natürlich den Fall ignorieren:

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