Omk*_*kar 3 generics kotlin kotlin-extension
为什么该程序在运行时应该因 ClassCastException 失败而打印 kotlin.Unit?
class Animal<T> {
}
fun <T> Animal<T>.extension(block: ()-> T){
print(block())
}
fun main(){
//(4 as Unit) //Runtime ClassCastException, OK
//Animal<String>().extension { 2+2 } //Compilation error, ok
Animal<Unit>().extension { 2+2 } // Why no ClassCastException but prints kotlin.Unit?
}
Run Code Online (Sandbox Code Playgroud)
如果这不是错误,是否可以强制执行约束?
在解释 lambda 表达式时,Kotlin 将返回 Unit 的函数视为特殊情况。如果它期望 lambda 返回 Unit,则无论 lambda 的最后一行计算结果如何,它都会隐式返回 Unit。否则,lambda 经常必须在末尾有一个无用的行来返回Unit
。因此,由于它解释 lambda 的方式,这里没有发生强制转换。在 lambda 定义的函数中有一个隐式的额外行返回 Unit。
假设您正在调用一个带有回调参数的函数fun foo(onComplete: (String)->Unit)
,并且您想要将返回值添加到 Set 中:
foo {
someMutableSet.add(it)
}
Run Code Online (Sandbox Code Playgroud)
该add
函数返回一个我们在这里不关心的布尔值。如果您必须记住像这样标记它,那会很烦人:
foo {
someMutableSet.add(it)
Unit
}
Run Code Online (Sandbox Code Playgroud)
这种特殊处理不仅仅适用于 lambda。您也不必return Unit
在每个返回 Unit 的传统函数的末尾添加一行。而且您也不必显式设置: Unit
函数签名的返回类型。
你的Int
没有被投射到Unit
. 实际上恰恰相反。您的() -> Int
lambda 被视为() -> Unit
lambda。具体来说,来自 lambda 表达式的文档(重点是我的),
lambda 表达式的完整语法形式如下:
Run Code Online (Sandbox Code Playgroud)val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }
...
- 如果 lambda 的推断返回类型不是
Unit
,则 lambda 主体内的最后一个(或可能是单个)表达式将被视为返回值。
所以在你的例子中,
Animal<Unit>().extension { 2+2 }
Run Code Online (Sandbox Code Playgroud)
{ 2+2 }
不是返回. Int
这是一个 lambda 返回Unit
,即没有任何价值。如果 lambda 的返回值能够使类型推断成功,Kotlin 很乐意简单地丢弃它。那是为了允许类似的事情
myButton.addEventListener { event ->
...
someFunctionThatHappensToReturnInt()
}
Run Code Online (Sandbox Code Playgroud)
如果 lambdaInt
仅仅因为我碰巧调用了一个返回 的函数(为了产生副作用)而推断出返回类型Int
,那将非常烦人,因此 Kotlin 会在必要时删除它。
如果您显式地编写该单词return
,您将强制参数的类型为() -> Int
您所期望的错误。
Animal<Unit>().extension { return 2+2; }
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
70 次 |
最近记录: |