Protocollo Swift Conformità facoltativa tramite Non facoltativo

Aug 18 2020

Ho un protocollo con una proprietà facoltativa.

La maggior parte dei tipi conformi a questo protocollo avrà una proprietà facoltativa corrispondente. Tuttavia, uno ha una proprietà non facoltativa dello stesso tipo e nome.

protocol SomeProtocol {
    var foo: Int? { get }
}

struct StructA: SomeProtocol {
    let foo: Int?
}

struct StructB: SomeProtocol {
    let foo: Int // Type 'StructB' does not conform to protocol 'SomeProtocol'
}

Premendo "Correggi - Vuoi aggiungere stub di protocollo?" pulsante aggiunge la versione facoltativa della proprietà, ma la struttura ora ha nomi di variabili duplicati non validi:

struct StructB: SomeProtocol {
    let foo: Int
    var foo: Int? { return foo } // Invalid redeclaration of 'foo'
}

Nel { get }solo caso, avevo ipotizzato che ciò avrebbe "funzionato" a causa del fatto che il non opzionale soddisfa sempre i vincoli dell'opzionale, in modo simile a come si può restituire un non opzionale in una funzione con un tipo di ritorno opzionale. Ma a quanto pare non è così.

Funziona allo stesso modo anche per le funzioni; un protocollo func bar() -> Int?non è soddisfatto da un tipo conforme che dichiara func bar() -> Int.

C'è un modo per aggirare questo problema? Preferirei non rinominare le variabili o aggiungere getter intermedi.

Questa situazione è stata considerata per Swift? Qual è il razionale per non consentire a un non opzionale di soddisfare una variabile di protocollo opzionale?

Risposte

pkamb Aug 19 2020 at 00:34

Se il protocollo fornisce un'implementazione predefinita che restituisce un facoltativo:

protocol SomeProtocol {
    var foo: Int? { get }
}

extension SomeProtocol {
    var foo: Int? { return nil }
}

i tipi conformi al protocollo possono quindi fornire una versione non facoltativa prioritaria della variabile/funzione:

struct StructB: SomeProtocol {
    let foo: Int
}

Ho trovato questo discusso sul forum Swift Evolution:

A prima vista ho pensato che ci fosse una regola che ci permette di soddisfare i requisiti del protocollo con tipi non opzionali, ma questo ha provocato un errore. Solo dopo ulteriori indagini ho notato che deve esistere un'implementazione predefinita per "sovrascrivere" il requisito con una versione non opzionale.

https://forums.swift.org/t/how-does-this-rule-work-in-regard-of-ambiguity/19448

Questo team di Swift discute anche di consentire ai tipi non facoltativi di soddisfare i protocolli di valore facoltativo:

Avrebbe senso consentire la soddisfazione dei requisiti del protocollo con tipi non opzionali, come con gli init fallibili? (Probabilmente con qualche promozione facoltativa implicita.)

Sì, totalmente! Ad eccezione della parte in cui questo cambia il comportamento del codice esistente, quindi dovremmo stare molto attenti. Questo è considerato parte del protocollo [SR-522] Le funzioni non possono avere rendimenti covarianti

che viene tracciato su Stack Overflow qui:

Perché un requisito di proprietà get-only in un protocollo non può essere soddisfatto da una proprietà conforme?