Błąd szybkiego kompilatora: Przypadek wyliczenia ma pojedynczą krotkę jako powiązaną wartość, ale tutaj jest kilka wzorców

12

Budując projekt w Xcode 11.4 beta 3, pojawia się błąd Swift Compiler na wyliczeniu:

Przypadek wyliczenia ma pojedynczą krotkę jako powiązaną wartość, ale istnieje tutaj kilka wzorców, domyślnie krotkując wzorce i próbując je dopasować

Kod źródłowy:

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

Resultjest ogólnym wyliczeniem z powiązanymi wartościami dla .errori .value. W tym przypadku powiązaną wartością jest krotka.

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

Nie przypominaj sobie wcześniej, aby widział ten błąd, a wyszukiwanie go nie przyniosło żadnych rezultatów. Jakieś pomysły?

Eneko Alonso
źródło
1
Zaktualizowałem pytanie, przepraszam, że to
pominęłem
Nie ma potrzeby ponownego tworzenia koła wyników; już istnieje. developer.apple.com/documentation/swift/result
matt
Ponadto nie ma jeszcze Xcode 11.4 beta 4 (jeszcze).
mat
Mój zły, miałem na myśli Xcode 11.4 beta 3. Jeśli chodzi o Result, zgadzam się, to stary kod, który poprzedza Swift.Result. Nie ma to jednak nic wspólnego z tym problemem.
Eneko Alonso
1
Całkowicie się zgadzam, staram się tylko wyjaśnić pytanie. Podnosisz tu dobry punkt, a to jest nasza szansa na udokumentowanie prawidłowego podejścia, które inni mogą znaleźć.
mat

Odpowiedzi:

14

Odkryłem, że możesz również wyciszyć ten błąd, traktując skojarzoną wartość bardziej jak krotkę, zawijając ją w dodatkowy zestaw nawiasów:

switch result {
case .error(let err):
    //
case .value((let staff, let locations)):  
    //
}
Wernzy
źródło
1
To miło, podoba mi się, dziękuję.
Eneko Alonso
2
Zastanów się nad przeniesieniem let, jeśli chcesz wszystko powiązać: case let .value( (staff, locations) ):i case .value( let (staff, locations) ):oba kompilują. Wybierz swoją ulubioną!
Jessy
1
Bardzo drobne, ale stylistycznie nie zgadzam się z powyższym komentarzem na temat wiązania wszystkiego za jednym razem. Posiadanie litery po lewej stronie związanej rzeczy jest łatwiejsze do odczytania i szybkiego zrozumienia, co jest związane. W przeciwnym razie musisz ekstrapolować mentalnie, co wiąże let. Wytyczne Google dotyczące kodowania swift również odradzają pojedynczy kaskadowy let: google.github.io/swift/#pattern-matching
ToddH
2
Wytyczne „Google”: /
Gee.E
9

Ok, rozgryzłem to. Wygląda na to, że enumz powiązanymi wartościami, w których typem wartości jest krotka, nie można już dopasować takiej instrukcji switch w ten sposób:

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

Rozwiązanie

Wartości z krotek należy ręcznie wyodrębnić w 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
źródło
To z pewnością jedno rozwiązanie.
mat
3

Jest to znany problem: https://developer.apple.com/documentation/xcode_release_notes/xcode_11_4_release_notes

Kod oparty na kompilatorze automatycznie tupujący wzorzec może prowadzić do błędu kompilatora podczas aktualizacji do Xcode 11.4, nawet jeśli kod został skompilowany wcześniej. (58425942)

Na przykład pominięcie nawiasów podczas włączania Opcjonalnego typu krotki powoduje błąd kompilatora:

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

}

Obejście : Dodaj dodatkowe nawiasy, aby jawnie krotnie wzorzec:

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

}

bolinhalouise
źródło
Dziękujemy za dodatkowe informacje i link do informacji o wersji. Tęsknie za tym.
Eneko Alonso
0

Jeśli mogę, chciałbym również dodać odpowiedź dla if casewersji.

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

a następnie oczywiście ignorując wielkość liter:

if case let .value(staff, _) = result {
    // Do something
}
Paul Peelen
źródło