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. 实际上恰恰相反。您的() -> Intlambda 被视为() -> Unitlambda。具体来说,来自 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 次 |
| 最近记录: |