为什么这个程序在运行时会因为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?
}

如果这不是一个错误,有可能强制执行约束吗?

推荐答案

在解释lambda表达式时,Kotlin将返回单元的函数视为特例.如果它期望lambda返回单位,则它将隐式返回单位,而不管lambda的最后一行的计算结果是什么.否则,lambdas通常必须在末尾有一个无用的行才能返回Unit.因此,由于它解释lambda的方式,这里没有发生演员阵容.在由lambda定义的函数中有一个隐式的额外行返回单元.

假设您正在调用一个接受回调参数fun foo(onComplete: (String)->Unit)的函数,并且希望将返回值添加到一个集合中:

foo {
    someMutableSet.add(it)
}

函数add返回一个我们在这里不关心的布尔值.如果你必须记住像这样标记它,那会很烦人:

foo {
    someMutableSet.add(it)
    Unit
}

这一特殊待遇不仅适用于Lambdas.您也不必在每个返回单元的传统函数的末尾加上return Unit行.而且您也不必显式地为函数签名设置返回类型: Unit.

Kotlin相关问答推荐

创建具有共同父类型的两种不同类型对象的列表的最有效方法是什么?

等待下一个值时暂停Kotlin Coroutine

Kotlin编译器如何决定是否可以在任何给定点调用Suspend方法?

使用 Kotlin 的 Springboot 中缺少 ResponseEntity 正文属性

修改器的属性是什么,我需要更改以使角变圆且宽度更小?喷气背包组合

在子类中覆盖 kotlin 运算符扩展函数

通用接口继承

第二个协程永远不会执行

如何在 kotlin 中使用带有泛型的密封类

Kotlin 编译器在构造函数中报告未使用的表达式,以便构建器采用 vararg lambda

测试协程和线程之间的差异,我在kotlin中使用线程时无法得到OOM错误

如何创建扩展函数isNullOrEmpty?

使用 Discord4j 交叉发布 Discord 消息

如何在kotlin中使用协程每秒调用一个函数

包括登录Elvis operator?

Android Room - error: Cannot figure out how to save this field into database

requireNotNull vs sure !! 操作符

在调用Kotlin数据类中的超类构造函数之前访问函数

如何解决:将Java类转换为Kotlin后出现error: cannot find symbol class ...?

如何在 IntelliJ IDEA 中禁用粘贴时将 Java 转换为 Kotlin?