Kotlin 2.2.20 现已发布!下个版本的特性抢先看!
大家吼!刚刚 Kotlin v2.2.20 已经发布, 更新的内容也已经在官网上更新:What's new in Kotlin 2.2.20 。 那么接下来,就让我来看看哪些是我最喜欢的新特性吧~!
注意!这里主要阐述一些我感兴趣的语言特性和库的更新。如果你还有其他关系的、但是我没有提到的,记得去官方日志看看喔~
下文中的代码示例等内容,如无特殊说明,均来自/改自官方更新日志。
语言特性
一如既往,让我们先来看看有哪些有趣的语言特性更新。
改进具有 suspend 的 Lambda 函数类型的重载解析
不知道你之前是否遇到这种情况,你定义了两个函数,它们的参数一个有 suspend,而一个没有。
当你需要调用它们的时候,IDE就分不清谁是谁了:
// Defines two overloads
fun transform(block: () -> Int) {}
fun transform(block: suspend () -> Int) {}
fun test() {
// Fails with overload resolution ambiguity
transform({ 42 })
// Uses an explicit cast, but the compiler incorrectly reports
// a "No cast needed" warning
transform({ 42 } as () -> Int)
}
可以看到,我们需要用强制类型转化 as () -> Int 来指明,但是这时候IDE又会提示你“非必要转化”。
现在,我们可以直接使用 suspend 来标记 Lambda 参数,解决上面提到的痛点了:
// Resolves to transform(() -> Int)
transform({ 42 })
// Resolves to transform(suspend () -> Int)
transform(suspend { 42 })
可以看到,直接使用 suspend { 42 } 即可指明使用带 suspend 的 Lambda 的那个对应的函数。
这个特性在下一个大版本也就是 2.3.0 中会默认启用。如果你现在就想体验,可以使用编译器参数:
-language-version 2.3
或者在 Gradle 构建脚本中配置语言版本:
kotlin {
compilerOptions {
languageVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_3)
}
}
执行表达式函数体中使用 return
在以前,你不能直接在一个表达式函数体中使用 return:
fun example() = return 42
// Error: Returns are prohibited for functions with an expression body
而现在,可以了!
// Specifies the return type explicitly
fun getDisplayNameOrDefault(userId: String?): String = getDisplayName(userId ?: return "default")
// Fails because it doesn't specify the return type explicitly
fun getDisplayNameOrDefault(userId: String?) = getDisplayName(userId ?: return "default")
不过对应地,你的函数需要显式标明返回值类型。同样地,在过去的版本中有些“取巧”的写法也可以达成直接在表达式中写 return,
并且不需要显式标明返回值类型,现在也对它们做了检测和弃用处理:
// Return type isn't explicitly specified, and the return statement is inside a lambda
// which will be deprecated
fun returnInsideLambda() = run { return 42 }
// Return type isn't explicitly specified, and the return statement is inside the initializer
// of a local variable, which will be deprecated
fun returnInsideIf() = when {
else -> {
val result = if (someCondition()) return "" else "value"
result
}
}
这个特性在下一个大版本也就是 2.3.0 中会默认启用。如果你现在就想体验,可以使用编译器参数:
-language-version 2.3
或者在 Gradle 构建脚本中配置语言版本:
kotlin {
compilerOptions {
languageVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_3)
}
}
基于数据流的表达式穷举性检查
在之前的版本中,Kotlin对一些内容(比如枚举)的穷举性检查只限定在 when 的范围内。
而现在,如果数据流表明了某些数据不会存在,那么 when 的穷举依然能够生效:
enum class UserRole { ADMIN, MEMBER, GUEST }
fun getPermissionLevel(role: UserRole): Int {
// Covers the Admin case outside of the when expression
if (role == UserRole.ADMIN) return 99
return when (role) {
UserRole.MEMBER -> 10
UserRole.GUEST -> 1
// You no longer have to include this else branch
// else -> throw IllegalStateException()
}
}
这个特性是实验性的,可以通过下面的编译器参数在 build.gradle.kts 中来启用它:
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xdata-flow-based-exhaustiveness")
}
}
在 catch 中支持 reified 类型
如字面意思所述,现在可以在有 reified 的 inline 函数中的 catch 中使用这个 reified 类型了:
inline fun <reified ExceptionType : Throwable> handleException(block: () -> Unit) {
try {
block()
// This is now allowed after the change
} catch (e: ExceptionType) {
println("Caught specific exception: ${e::class.simpleName}")
}
}
fun main() {
// Tries to perform an action that might throw an IOException
handleException<java.io.IOException> {
throw java.io.IOException("File not found")
}
// Caught specific exception: IOException
}
这个特性是实验性的,可以通过下面的编译器参数在 build.gradle.kts 中来启用它:
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xallow-reified-type-in-catch")
}
}
改进 Kotlin 的 contracts
在 2.2.20,Kotlin 改进了一些跟 contracts 相关的东西:
- Support for generics in contract type assertions.
支持在契约类型断言中使用泛型。 - Support for contracts inside property accessors and specific operator functions.
支持在属性访问器和特定运算符函数中使用契约。 - Support for the
returnsNotNull()function in contracts, allowing you to assume conditions are true when passed inside lambdas.
支持在契约中使用returnsNotNull()函数,允许你在 lambda 内部假设条件为真。 - New
holdsInkeyword as a way to ensure a non-null return value when a condition is met.
新增holdsIn关键字,用于在满足条件时确保返回值非空。
虽然这东西平时写代码的时候用的会比较少,不过如果是一个库作者或者官方的std中,倒也没那么少见。
这些新的东西也都是实验性的。使用它们会有对应的
@OptIn需要你去标记,以及还有各自对应的编译器参数。