Próbujemy ustalić, czy jest to błąd w Swift, czy w niewłaściwym używaniu generycznych, opcji, typu wnioskowania i/lub operatora zerowego koalescencji.Wnioskowanie o typ nie powiedzie się, gdy używamy operatora koalesczenia zerowego z dwoma opcjami.
Nasza struktura zawiera kod do analizowania słowników w modelach i mamy problem z opcjonalnymi właściwościami z wartościami domyślnymi.
Mamy protokół SomeProtocol
i dwie funkcje standardowych określonych w rozszerzeniem protokołu:
mapped<T>(...) -> T?
mapped<T : SomeProtocol>(...) -> T?
Nasze elemencie i klas przywierania do tego protokołu, a następnie zanalizować ich właściwości wewnątrz funkcji init wymaganych przez protokół.
Wewnątrz funkcji init(...)
staramy się ustawić wartość właściwości someNumber
tak:
someNumber = self.mapped(dictionary, key: "someNumber") ?? someNumber
Słownik oczywiście zawiera rzeczywistą wartość dla klucza someNumber
. Jednak zawsze będzie się to nie udać, a rzeczywista wartość nigdy nie zostanie zwrócona z funkcji mapped()
.
Komentowanie drugiej funkcji ogólnej lub wymuszenie downcastowania wartości na rhs zadania spowoduje naprawienie tego problemu, ale uważamy, że powinno to działać tak, jak jest obecnie napisane.
Poniżej znajduje się pełny kod urywek wykazując problemu, wraz z dwoma opcjami (tymczasowo) Rozwiązać problem oznaczony OPTION 1
i OPTION 2
w kodzie:
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)")
}
proszę zauważyć, że jest to przykład, który pomija faktyczne implementacje funkcji mapped
, ale wynik jest identyczny i dla zachowania tego pytania kod powinien wystarczyć.
EDIT: I zgłosił ten problem jakiś czas temu, a teraz zostało oznaczone jako stałe, więc mam nadzieję, że to nie powinno się zdarzyć już w Swift 3.
https://bugs.swift.org/browse/SR-574
To bardzo dobre wytłumaczenie. Rozumiem twój punkt widzenia i mogę zrozumieć, dlaczego "someNumber!" Działa, chociaż nie jestem pewien, czy widzę, dlaczego kod działa zgodnie z oczekiwaniami, kiedy komentujesz funkcję 'mapowaną ...' . Czy mógłbyś powiedzieć coś więcej na ten temat? –
Takie opcje, bardzo bóle głowy. :RE –