Stiamo cercando di capire se si tratta di un bug in Swift o di abuso di generici, optionals, inferenza di tipo e/o operatore a coalescenza nil.L'inferenza di tipo fallisce quando si utilizza l'operatore a coalescenza nulla con due optionals
La nostra struttura contiene del codice per l'analisi dei dizionari in modelli e abbiamo riscontrato un problema con proprietà facoltative con valori predefiniti.
Abbiamo un protocollo SomeProtocol
e due funzioni generiche definite in un protocollo di estensione:
mapped<T>(...) -> T?
mapped<T : SomeProtocol>(...) -> T?
nostre strutture e classi aderire a questo protocollo e quindi analizzare le loro proprietà all'interno di una funzione init richiesto dal protocollo.
All'interno della funzione init(...)
cerchiamo di impostare un valore della proprietà someNumber
in questo modo:
someNumber = self.mapped(dictionary, key: "someNumber") ?? someNumber
Il dizionario, naturalmente, contiene il valore effettivo per la chiave someNumber
. Tuttavia, questo fallirà sempre e il valore effettivo non verrà mai restituito dalla funzione mapped()
.
O commentare la seconda funzione generica o forzare il downcasting del valore sul rhs del compito risolverà questo problema, ma pensiamo che questo dovrebbe funzionare nel modo in cui è attualmente scritto.
Qui di seguito è un frammento di codice completo che dimostra la questione, insieme a due opzioni che (temporaneamente) risolvere il problema con l'etichetta OPTION 1
e OPTION 2
nel codice:
import Foundation
// Some protocol
protocol SomeProtocol {
init(dictionary: NSDictionary?)
}
extension SomeProtocol {
func mapped<T>(dictionary: NSDictionary?, key: String) -> T? {
guard let dictionary = dictionary else {
return nil
}
let source = dictionary[key]
switch source {
case is T:
return source as? T
default:
break
}
return nil
}
// ---
// OPTION 1: Commenting out this makes it work
// ---
func mapped<T where T:SomeProtocol>(dictionary: NSDictionary?, key: String) -> T? {
return nil
}
}
// Some struct
struct SomeStruct {
var someNumber: Double? = 0.0
}
extension SomeStruct: SomeProtocol {
init(dictionary: NSDictionary?) {
someNumber = self.mapped(dictionary, key: "someNumber") ?? someNumber
// OPTION 2: Writing this makes it work
// someNumber = self.mapped(dictionary, key: "someNumber") ?? someNumber!
}
}
// Test code
let test = SomeStruct(dictionary: NSDictionary(object: 1234.4567, forKey: "someNumber"))
if test.someNumber == 1234.4567 {
print("success \(test.someNumber!)")
} else {
print("failure \(test.someNumber)")
}
Si prega di notare, che questo è un esempio che manca le effettive implementazioni delle funzioni mapped
, ma il risultato è identico e per motivi di questa domanda il codice dovrebbe essere sufficiente.
EDIT: avevo segnalato questo problema un po 'indietro e ora è stato contrassegnato come fisso, quindi speriamo che questo non deve accadere più a Swift 3.
https://bugs.swift.org/browse/SR-574
Questa è una spiegazione molto buona. Riesco a vedere il tuo punto e posso capire perché funziona 'someNumber!', Anche se non sono sicuro se vedo perché il codice funziona come previsto quando commenta la funzione 'mapped ...' . Potresti commentare un po 'di più su questo? –
Tali optionals, molto mal di testa. : D –