2015-11-11 15 views
5

Jeśli rozumiem to poprawnie, Swift może określić rzeczywisty rodzaj leków generycznych za pomocą różnych środków, w tym dopasowywania przez typ zwrotu. Ten sam (lub podobny) mechanizm służy do rozróżniania przeciążonych funkcji. Tak to działa zgodnie z oczekiwaniami:Swift rodzajowy wybór nie propaguje

func getValue<T>()->T? { 
    return nil 
} 

func getValue()->Int? { 
    return 13 
} 

let b: Int? = getValue() 

Uruchamiając ten, b będą 13. Pod względem technicznym oba sygnatury funkcji są dopasowane, ale te ostatnie są bardziej specyficzne dla żądanego typu zwrotu.

Dodajmy drugą funkcję i tunel zaproszeniu przez niego:

func getGetValue<T>()->T? { 
    return getValue() 
} 

let c: Int? = getGetValue() 

Uruchamiając ten, c będzie nil. W rzeczywistości kompilator wybierze ogólną implementację getValue(), która będzie wywoływana z getGetValue(), co nie jest tym, czego potrzebuję. IMHO, żądany typ zwracany powinien rozprzestrzeniać się za pośrednictwem drugiego generycznego, wybierając między dwiema implementacjami getValue(), powodując zachowanie takie samo jak w pierwszym przykładzie.

Czego mi brakuje? (Xcode 7.1)

+0

Doskonałe znalezisko. Domyślam się, że typ "domniemany przez zwrot" nie działa, gdy istnieje kolejna warstwa abstrakcji. Wewnątrz 'getGetValue', kompilator nie ma pojęcia, że ​​typ' T' jest, więc pierwsza funkcja jest jedyną, która pasuje. –

+0

@ZoffDino To również moje przypuszczenie, ale nie rozumiem, dlaczego kompilator nie może propagować typów z dołu do góry. Z mojego punktu widzenia wygląda na błąd - ale nie jestem kompilatorem. Być może istnieje całkowicie uzasadniony powód takiego zachowania. Złożę radar, na wszelki wypadek. –

+0

W blogu Swift znajduje się wpis [Bezpieczeństwo pamięci: zapewnienie wartości są definiowane przed użyciem] (https://developer.apple.com/swift/blog/?id=28), który omawia, jak daleko kompilator idzie, aby udowodnić poprawność programu. Myślę, że jest to trochę istotne dla twojego pytania –

Odpowiedz

0

Próbowałem jawnie propagują typ rodzajowy i nadal nie działa (tak masz rację to jest problem):

func getGetValue<T>()->T? { 
    guard let value: T? = getGetValue() 
    return value 
} 

Tutaj jest nieco inaczej jednak, że podejście może uzyskać to, czego szukasz za pomocą protokołu (użycie protokołu pozwala nam zachować pewne informacje o typie)

// Protocol for getting a value 
protocol GetValue { 
    static func getValue() -> Self? 
} 

// Default implementation 
extension GetValue { 
    static func getValue() -> Self? { 
     return nil 
    } 
} 

// Int implementation 
extension Int: GetValue { 
    static func getValue() -> Int? { 
     return 13 
    } 
} 

// Our generic getGetValue function for any type that implements GetValue 
func getGetValue<T: GetValue>()->T? { 
    return T.getValue() 
} 

let a: Int? = getGetValue() // 13 

// Making String implement the protocol (It gets the default implementation) 
extension String: GetValue { 

} 

let b: String? = getGetValue() // nil 
Powiązane problemy