2015-11-11 2 views
5

Se ho capito bene, Swift può determinare il tipo effettivo di generici con diversi mezzi, incluso il matching per tipo di ritorno. Lo stesso meccanismo (o un meccanismo simile) è usato per disambiguare le funzioni sovraccariche. Quindi, questo funziona come previsto:La selezione del tipo generico Swift non si propaga

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

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

let b: Int? = getValue() 

Quando si esegue questa, b sarà 13. Tecnicamente, entrambe le firme delle funzioni sono adeguate, ma quest'ultima è più specifica del tipo di reso richiesto.

Aggiungiamo una seconda funzione e la chiamata tunnel attraverso di esso:

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

let c: Int? = getGetValue() 

Quando si esegue questa operazione, c sarà nil. Infatti, il compilatore selezionerà l'implementazione generica getValue() da chiamare da getGetValue(), che non è quello che voglio. IMHO, il tipo di reso richiesto deve propagarsi attraverso il secondo generico quando si sceglie tra le due implementazioni di getValue(), con lo stesso comportamento del primo esempio.

Cosa mi manca? (Xcode 7.1)

+0

Eccellente scoperta. La mia ipotesi è che infer-by-return-type non funzioni quando c'è un altro livello di astrazione. Una volta all'interno di 'getGetValue', il compilatore non ha idea che il tipo' T' sia, quindi la prima funzione è l'unica che corrisponde. –

+0

@ZoffDino Questa sarebbe la mia ipotesi, ma non capisco perché il compilatore non possa propagare i tipi dal basso verso l'alto. Dal mio punto di vista, sembra un insetto - ma non sono un tipo da compilatore. Forse c'è un motivo perfettamente valido per questo comportamento. Inserirò un radar, per ogni evenienza. –

+0

C'è una voce nel blog Swift [Sicurezza della memoria: i valori di sicurezza sono definiti prima dell'uso] (https://developer.apple.com/swift/blog/?id=28) che spiega fino a che punto il compilatore va a dimostrare la correttezza del programma. Penso che sia in qualche modo pertinente alla tua domanda –

risposta

0

ho cercato di diffondere in modo esplicito il tipo generico e ancora non funziona (Quindi hai ragione questo è un problema):

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

Qui è un approccio leggermente diverso, tuttavia, che potrebbe ottenere quello che stai cercando usando un protocollo (Usando un protocollo ci permette di mantenere alcune informazioni di tipo)

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