11月16日 JetBrains 正式发布了 Kotlin 1.6.0,这个版本根据一些反馈,将上一版本中的一些实验的语法特性进行了转正。例如
- Sealed exhaustive whens
- Suspending functions as supertypes
- ...
Sealed exhaustive whens
当我们在 when 中使用诸如枚举、密封类/接口等可穷举类型时,某些情况下可能写出不安全的代码
sealed class Contact { data class PhoneCall(val number: String) : Contact() data class TextMessage(val number: String) : Contact() data class InstantMessage(val type: IMType, val user: String) : Contact() }
如上,定义了三个子类的密封类
fun Rates.computeMessageCost(contact: Contact): Cost = when (contact) { // ERROR: 'when' expression must be exhaustive is Contact.PhoneCall -> phoneCallCost is Contact.TextMessage -> textMessageCost }
此时如果 case 后跟的是一个表达式, 则如果 case 分支没有穷举所有子类,编译器会报错
但是如果如果 case 后个的是一个语句,如下
fun sendAnnouncement(contact: Contact, announcement: Announcement) { when (contact) { is Contact.PhoneCall -> schedulePhoneCall(contact.number, announcement) is Contact.TextMessage -> sendTextMessage(contact.number, announcement) } }
此时即使没有穷举所有子类,编译器也不会报错,这可能会造成不必要的bug
Kotlin 1.6 在这种情况下,编译器会给出 Warning ,按计划 1.7 之后 Warning 会改为 Error,强制开发者补齐所有分支逻辑,避免出现 Bug
Suspending functions as supertypes
Kotlin 中许多 API 都以函数类型作为参数。当你需要调用这些 API 时,需要传入一个函数类型的实例。而当你想在实例中封装一些可复用的逻辑时,可以使用函数类型作为父类创建子类。
但是这种做法目前不适用于挂起函数,你无法继承一个 suspend
函数类型的父类
class C : suspend () -> Unit { // Error: Suspend function type is not allowed as supertypes } C().startCoroutine(completion = object : Continuation<Unit> { override val context: CoroutineContext get() = TODO("Not yet implemented") override fun resumeWith(result: Result<Unit>) { TODO("Not yet implemented") } })
Kotlin 1.5.30 在 Preveiw 中引入了此特性,可以继承一个 suspend 的函数类型
class MyClickAction : suspend () -> Unit { override suspend fun invoke() { TODO() } } fun launchOnClick(action: suspend () -> Unit) {}
如上,你现在可以这样调用 launchOnClick(MyClickAction())
。
1.6 中将此 feature 默认打开。
此外 1.6 还加入了其他一些新的语法特性,详情可以参考:blog.jetbrains.com/kotlin/2021…