我有以下功能:
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
但是processEmpty
没有编译。错误消息为Type mismatch: inferred type is () -> kotlin.Unit but (kotlin.Unit) -> kotlin.Unit was expected
。但是,如果我将此功能更改为
fun <T> processEmpty2(t: T, call: (Unit) -> Unit) = process(t, call, {}) // OK
那么() -> Unit
和(Unit) -> Unit
类型之间有什么区别?为什么第一版processEmpty
没有编译?
答案 0 :(得分:27)
Unit
实际上是type that has exactly one value(值Unit
本身;此外,这就是它被命名为Unit
)的原因。它对应于Java中的void
,但它不一样。
Kotlin编译器将没有声明返回值的函数视为Unit
-returning functions,并且也可以省略return Unit
。这就是{ }
是单位返回函数的原因。
但这不适用于参数。要严格,当您使用Unit
参数或(Unit) -> Unit
函数变量声明函数时,必须在调用站点传递类型为Unit
的参数。唯一要传递的值是Unit
。
没有像{ doSomething() }
这样的指定参数的lambda既被视为没有参数的函数,也被视为具有单个隐式参数it
的函数。您可以将{ }
用作() -> Unit
和(Unit) -> Unit
。
对于呼叫站点,如上所述,必须传递Unit
:
val f: (Unit) -> Unit = { println("Hello") }
f(Unit) // the only valid call
() -> Unit
函数不需要传递参数:
val f: () -> Unit = { println("Hello") }
f() // valid call
<小时/> 在您的示例中,类型推断发生如下:
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
map: (T) -> U = { }
,因此从U
返回的Unit
替换{ }
。call
应为(Unit) -> Unit
。call: () -> Unit
与(Unit) -> Unit
不同,如上所述。错误。