Errore del compilatore Swift: il caso enum ha una singola tupla come valore associato, ma qui ci sono diversi schemi


12

Costruendo un progetto in Xcode 11.4 beta 3, visualizzo questo errore del compilatore Swift su un enum:

Il caso enum ha una singola tupla come valore associato, ma qui ci sono diversi schemi, che ne implicano la tlicazione implicita e cercano invece di abbinarlo

Codice sorgente:

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

Resultè un enum generico con valori associati per .errore .value. In questo caso, il valore associato è un tupple.

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

Non ricordare di aver visto questo errore prima e di averlo cercato non ha prodotto risultati. Qualche idea?


1
Ho aggiornato la domanda, scusami per averlo lasciato fuori
Eneko Alonso l'

Non è necessario reinventare la ruota dei risultati; esiste già. developer.apple.com/documentation/swift/result
matt

Inoltre, non esiste Xcode 11.4 beta 4 (ancora).
matt

Mio male, intendevo Xcode 11.4 beta 3. Per quanto riguarda Result, sono d'accordo, è il vecchio codice che precede Swift.Result. Tuttavia, ciò non ha nulla a che fare con il problema.
Eneko Alonso,

1
Sono completamente d'accordo, sto solo cercando di ripulire la domanda. Sollevi un buon punto qui e questa è la nostra occasione per documentare gli approcci corretti che gli altri possano trovare.
matt

Risposte:


14

Ho scoperto che puoi anche mettere a tacere questo errore trattando il valore associato più come una tupla avvolgendolo in un set aggiuntivo di parentesi:

switch result {
case .error(let err):
    //
case .value((let staff, let locations)):  
    //
}

1
È carino, mi piace, grazie.
Eneko Alonso,

2
Considera di spostare letfuori se hai intenzione di legare tutto, però: case let .value( (staff, locations) ):ed case .value( let (staff, locations) ):entrambi compilare. Scegli il tuo preferito!
Jessy

1
Super minore ma stilisticamente non sono d'accordo con il commento di cui sopra sull'associazione di tutto con un singolo let. Avere il permesso alla sinistra della cosa legata è più facile da leggere e capire rapidamente quali cose sono legate. Altrimenti devi estrapolare mentalmente ciò che il let è vincolante. Le linee guida per la codifica di Google per swift sconsigliano anche la singola cascata: google.github.io/swift/#pattern-matching
ToddH

2
Linee guida "di Google": /
Gee.E

9

Ok, capito. Sembra che enumcon i valori associati, in cui il tipo di valore è un tupple, non può più essere associato su un'istruzione switch come quella:

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

Soluzione

I valori da tupple devono essere estratti manualmente in 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
    // 
}

Questa è certamente una soluzione.
matt

3

Questo è un problema noto: https://developer.apple.com/documentation/xcode_release_notes/xcode_11_4_release_notes

Il codice che si basa sul compilatore che fa automaticamente il tupling di un modello può portare a un errore del compilatore durante l'aggiornamento a Xcode 11.4, anche se il codice compilato in precedenza. (58425942)

Ad esempio, tralasciando le parentesi quando si attiva un'opzione di tipo tupla si verifica un errore del compilatore:

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

}

Soluzione alternativa : aggiungere parentesi aggiuntive per correggere in modo esplicito il modello:

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

}


Grazie per le informazioni aggiuntive e collegamento alle note di rilascio. Ho perso questo.
Eneko Alonso,

0

Se posso, vorrei aggiungere anche una risposta per la if caseversione.

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

e poi ovviamente ignorando il caso:

if case let .value(staff, _) = result {
    // Do something
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.