2016-02-12 5 views
9

devo seguenti funzioni:Qual è la differenza tra() -> Unità e (Unità) -> Tipi di unità?

fun <T, U> process(t: T, call: (U) -> Unit, map: (T) -> U) = call(map(t)) 

fun <T> processEmpty(t: T, call:() -> Unit) = process(t, call, {}) // error 

ma il processEmpty non è la compilazione. Il messaggio di errore è Type mismatch: inferred type is() -> kotlin.Unit but (kotlin.Unit) -> kotlin.Unit was expected. Ma se cambio questa funzione per

fun <T> processEmpty2(t: T, call: (Unit) -> Unit) = process(t, call, {}) // OK 

Allora, qual è la differenza tra () -> Unit e (Unit) -> Unit tipi? Perché la prima versione di processEmpty non si sta compilando?

+0

ho trovato, credo, il modo migliore per definire 'funzione processEmpty':' divertente processEmpty (t: T, chiamare:() -> Unità) = processo (t, {call()}, {}) ' – netimen

+0

Sì,' {call()} 'è una funzione corretta di un argomento (implicito' it'), quindi può essere passato come '(Unità) -> Unità'. – hotkey

risposta

19

Unit è in realtà un type that has exactly one value (il valore è Unit stessa, anche, questo è il motivo per cui prende il nome Unit). Corrisponde a void in Java, ma non è la stessa cosa.

Le funzioni di compilazione di Kotlin senza valore di ritorno dichiarato come Unit-returning functions e return Unit possono anche essere omesse. Questo è il motivo per cui { } è una funzione di ritorno unità.

Ma questo non si applica agli argomenti. Per essere severi, quando si dichiara una funzione con argomento Unit o variabile di funzione (Unit) -> Unit, è necessario passare un argomento di tipo Unit sul sito di chiamata. L'unico valore da passare è Unit.

Un lambda senza argomenti specifici come { doSomething() } viene trattato sia come una funzione senza argomenti e come una funzione con singolo argomento implicito it. È possibile utilizzare { } sia come () -> Unit e (Unit) -> Unit.

Per quanto riguarda il sito di chiamata, come detto sopra, Unit deve essere superato:

val f: (Unit) -> Unit = { println("Hello") } 

f(Unit) // the only valid call 

Considerando che () -> Unit funzioni non è necessario un argomento per essere passato:

val f:() -> Unit = { println("Hello") } 

f() // valid call 


Nella tua esempio, l'inferenza di tipo avviene come segue:

fun <T, U> process(t: T, call: (U) -> Unit, map: (T) -> U) = call(map(t)) 

fun <T> processEmpty(t: T, call:() -> Unit) = process(t, call, {}) // error 
  1. map: (T) -> U = { }, quindi una sostituzione per U è Unit restituita da { }.
  2. Pertanto call deve essere (Unit) -> Unit.
  3. call:() -> Unit che non corrisponde a (Unit) -> Unit, come indicato sopra. Errore.