Kotlin 2.3.20-Beta1 最新变化
本文档并未涵盖抢先体验计划 (EAP) 版本的所有功能, 但它重点介绍了其中的一些重大改进。
欲查看完整的更改列表,请参阅 GitHub 变更日志。
Kotlin 2.3.20-Beta1 版本已发布!以下是此 EAP 版本的一些详细信息:
- 语言: 稳定的上下文参数、显式支持字段以及注解使用处目标的多个功能
- 标准库: 稳定的 UUID 以及 对检查排序顺序的支持
- Kotlin/JVM: 支持 Java 26 以及 默认启用元数据中的注解
- Kotlin/Native: 支持将 Swift 软件包作为依赖项、Swift 导出的更新以及默认的 CMS GC
- Kotlin/Wasm: 默认启用增量编译以及对 WebAssembly 组件模型的支持
- Kotlin/JS: 支持 value class 导出以及 JS 代码内联中的 ES2015 功能
- Gradle: 兼容 Gradle 9.4.1
- Maven: Java 与 JVM 目标版本之间的自动对齐
- Kotlin 编译器: 在
.klib编译期间更加一致的内联函数行为
有关 Kotlin 发布周期的信息,请参阅 Kotlin 发布流程。
更新到 Kotlin 2.3.20-Beta1
最新版本的 Kotlin 已包含在最新版本的 IntelliJ IDEA 和 Android Studio 中。
要更新到新的 Kotlin 版本,请确保您的 IDE 已更新至最新版本,并在您的构建脚本中将 Kotlin 版本更改为 2.3.20-Beta1。
新功能 {id=new-stable-features}
在之前的 Kotlin 版本中,有几项新功能作为实验性功能引入。 以下功能现已在 Kotlin 2.3.20-Beta1 中晋升为稳定阶段,因此您不再需要显式启用即可使用它们:
- 上下文参数,除了上下文实参和可调用引用
- 属性的
@all元目标 - 注解使用处目标的新默认规则
- 显式支持字段
- 公共 Kotlin 标准库中稳定的 UUID
- 对检查排序顺序的支持
- 用于在 JVM 上将无符号整数转换为
BigInteger的新 API - 支持将 value class 导出到 JavaScript/TypeScript
- 内联 JS 代码时支持 ES2015 功能
- Maven:Java 与 JVM 目标版本之间的自动对齐
新功能 {id=new-experimental-features}
语言
Kotlin 2.3.20-Beta1 将上下文参数、显式支持字段和注解使用处目标功能提升为稳定阶段。 此版本还引入了上下文参数的显式上下文实参。
稳定功能
Kotlin 2.2.0 引入了一些作为实验性的语言功能。我们很高兴地宣布,以下语言功能在此版本中现已稳定:
上下文参数的显式上下文实参
Kotlin 2.3.20-Beta1 为上下文参数引入了显式上下文实参。
Kotlin 2.3.20 更改了上下文参数的重载解析。 因此,仅在上下文参数上存在差异的重载调用可能会产生歧义。
您现在可以通过在调用站点传递显式上下文实参来解决此歧义。
示例如下:
class EmailSender
class SmsSender
context(emailSender: EmailSender)
fun sendNotification() {
println("Sent email notification")
}
context(smsSender: SmsSender)
fun sendNotification() {
println("Sent SMS notification")
}
context(defaultEmailSender: EmailSender, defaultSmsSender: SmsSender)
fun notifyUser() {
// 选择带有 EmailSender 上下文参数的重载
sendNotification(emailSender = defaultEmailSender)
// 选择带有 SmsSender 上下文参数的重载
sendNotification(smsSender = defaultSmsSender)
}您还可以使用显式上下文实参代替 context() 函数,以减少嵌套并使某些调用更易读。 如果您需要在多次调用中使用相同的上下文实参,请改用 context() 函数。
此功能处于实验性阶段。要显式启用它,请在您的构建文件中添加以下编译器选项:
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xexplicit-context-arguments")
}
}<build>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<configuration>
<args>
<arg>-Xexplicit-context-arguments</arg>
</args>
</configuration>
</plugin>
</plugins>
</build>欲了解更多信息,请参阅该功能的 KEEP。
支持集合字面量
Kotlin 2.3.20-Beta1 引入了对集合字面量的实验性支持。您现在可以使用方括号 [] 以更简洁的方式创建集合。
例如:
fun main() {
// 带有显式类型声明的可变列表
// val shapes: MutableList<String> = mutableListOf("triangle", "square", "circle")
// 使用方括号语法的可变列表
val shapes: MutableList<String> = ["triangle", "square", "circle"]
println(shapes)
// [triangle, square, circle]
}目前,集合字面量无法用于构造在 Java 中定义的集合。有关更多信息,请参阅 KT-80494。
如果编译器没有足够的信息来推断集合类型,它将默认为 List 类型:
fun main() {
val fruit = ["apple", "banana", "cherry"]
println(fruit)
// [apple, banana, cherry]
}您还可以声明自定义 operator fun of 函数,以便对您自己的类型使用方括号语法。例如,如果您有以下 DoubleMatrix 类:
class DoubleMatrix(vararg val rows: Row) {
companion object {
operator fun of(vararg rows: Row) = DoubleMatrix(*rows)
}
class Row(vararg val elements: Double) {
companion object {
operator fun of(vararg elements: Double) = Row(*elements)
}
}
}您可以像这样创建一个 identityMatrix 类实例:
fun main() {
val identityMatrix: DoubleMatrix = [
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
]
}在此示例中,编译器将嵌套的集合字面量转换为对相应 operator fun of 函数的调用。编译器递归地解析这些调用,并使用预期类型来选择正确的重载。
此功能处于实验性阶段。要显式启用它,请在您的构建文件中添加以下编译器选项:
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xcollection-literals")
}
}<build>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<configuration>
<args>
<arg>-Xcollection-literals</arg>
</args>
</configuration>
</plugin>
</plugins>
</build>欲了解更多信息,请参阅该功能的 KEEP。
改进的编译时常量
Kotlin 2.3.20-Beta1 为编译时常量带来了实验性改进,使对数值和字符串类型的支持更加一致且更易于使用。这些改进包括支持:
- 无符号类型操作。
- 标准库中的字符串函数,如
.lowercase()、.uppercase()和.trim()函数。 - 对枚举常量的
.name属性以及KCallable接口的求值。
为了明确哪些函数在编译时求值,Kotlin 2.3.20-Beta1 引入了 IntrinsicConstEvaluation 注解。 有些函数已在编译时求值,但尚未添加该注解。后续版本将为剩余函数添加该注解。有关支持的函数列表,请参阅 KEEP 附录。
此功能处于实验性阶段。要显式启用它,请在您的构建文件中添加以下编译器选项:
kotlin {
compilerOptions {
freeCompilerArgs.add("-XXLanguage:+IntrinsicConstEvaluation")
}
}<build>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<configuration>
<args>
<arg>-XXLanguage:+IntrinsicConstEvaluation</arg>
</args>
</configuration>
</plugin>
</plugins>
</build>欲了解更多信息,请参阅该功能的 KEEP。
标准库
Kotlin 2.3.20-Beta1 稳定了公共 Kotlin 标准库中对 UUID 的支持。它还在 JVM 上添加了用于将无符号整数转换为 BigInteger 的新扩展函数,并增加了对检查排序顺序的支持。
公共 Kotlin 标准库中稳定的 UUID
Kotlin 2.0.20 引入了一个用于生成 UUID 的类(通用唯一标识符),并增加了对在 Kotlin 和 Java UUID 之间进行转换的支持。后续版本逐步改进了这一实验性功能,增加了对以下内容的支持:
在 Kotlin 2.3.20-Beta1 中,kotlin.uuid.Uuid API 晋升为稳定阶段。 唯一的例外是用于生成 V4 和 V7 UUID 的函数,它们仍处于实验性阶段且仍需显式启用。
对检查排序顺序的支持
Kotlin 2.3.20-Beta1 添加了新的扩展函数,用于检查可迭代对象、数组和序列中的排序顺序。
这包括以下扩展函数:
.isSorted().isSortedDescending().isSortedWith(comparator).isSortedBy(selector).isSortedByDescending(selector)
您可以使用这些扩展函数来检查元素是否已经排序,而无需重新排序或创建自己的帮助程序函数。 如果元素按指定顺序排列,或者元素少于两个,则它们返回 true,否则返回 false。 这些函数在遇到无序对时会立即停止,这使得它们在处理大型输入时非常高效。
以下是使用 .isSorted() 和 .isSortedBy() 函数检查排序顺序的示例:
data class User(val name: String, val age: Int)
fun main() {
val numbers = listOf(1, 2, 3, 4)
println(numbers.isSorted())
// true
val users = listOf(
User("Alice", 24),
User("Bob", 31),
User("Charlie", 29),
)
println(users.isSortedBy(User::age))
// false
}我们欢迎您在 YouTrack 中提供反馈。
用于在 JVM 上将无符号整数转换为 BigInteger 的新 API
Kotlin 2.3.20-Beta1 在 JVM 上引入了 UInt.toBigInteger() 和 ULong.toBigInteger() 扩展函数。
此前,将 UInt 和 ULong 值转换为 BigInteger 需要基于字符串的变通方法或自定义转换逻辑。 从 Kotlin 2.3.20-Beta1 开始,您现在可以使用 .toBigInteger() 直接将无符号整数值转换为 BigInteger。
示例如下:
fun main() {
val unsignedLong = Long.MAX_VALUE.toULong() + 1uL
val unsignedInt = UInt.MAX_VALUE
println(unsignedLong.toBigInteger())
// 9223372036854775808
println(unsignedInt.toBigInteger())
// 4294967295
}我们欢迎您在 YouTrack 中提供反馈。
Kotlin/JVM
Kotlin 2.3.20-Beta1 支持新的 Java 版本,并默认启用元数据中的注解。
支持 Java 26
从 Kotlin 2.3.20-Beta1 开始,编译器可以生成包含 Java 26 字节码的类。
默认启用元数据中的注解
Kotlin 2.2.0 中的 Kotlin Metadata JVM 库引入了对读取存储在 Kotlin 元数据中注解的支持。通过此支持,Kotlin 编译器将注解与 JVM 字节码一起写入元数据中,使它们可以被 Kotlin Metadata JVM 库访问。因此,注解处理器和其他工具可以在元数据级别理解和操作这些注解,而无需使用反射或修改源代码。
在 Kotlin 2.3.20-Beta1 中,此支持默认启用。
Kotlin/Native
Kotlin 2.3.20-Beta1 带来了对 Swift 软件包导入的支持,通过 Swift 导出改进了互操作性,并在垃圾回收器中默认启用了并发标记。
Swift 软件包导入
Kotlin Multiplatform 项目现在可以在其 Gradle 配置中为 iOS 应用声明 Swift 软件包作为依赖项:
// build.gradle.kts
kotlin {
swiftPMDependencies {
swiftPackage(
url = url("https://github.com/firebase/firebase-ios-sdk.git"),
version = from("12.11.0"),
products = listOf(
product("FirebaseAI"),
product("FirebaseAnalytics"),
...
}有关工作示例和更详细的信息,请参阅 SwiftPM 导入。
如果您的项目依赖于 CocoaPods 依赖项,您可以将当前设置迁移为使用 Swift 软件包。KMP 工具考虑到了这一用例,并帮助您自动重新配置项目。有关详情,请参阅我们的 CocoaPods 迁移指南。
Swift 导出:支持导出协程流
Kotlin 2.3.20-Beta1 通过 Swift 导出进一步改进了 Kotlin 与 Swift 的互操作性,增加了对将 kotlinx.coroutines 流导出到 Swift 的支持。
kotlinx.coroutines 中的流(Flow)代表可以并发发送和消费的异步数据流。它们通常用于响应式编程模式,例如监听数据库更新、网络请求或 UI 事件。
此前,将 Flow 接口从 kotlinx.coroutines.flow 暴露给 Swift 的唯一方法是通过第三方解决方案。现在,您可以开箱即用地将流导出到 Swift 的惯用对应物:AsyncSequence。
该功能默认启用。您可以将任何具有 Flow 类型的公共 API 导出到 Swift,同时保留类型信息。 例如:
// Kotlin
// 导出 Flow 时保留 String 类型
fun flowOfStrings(): Flow<String> = flowOf("hello", "any", "world")// Swift
var actual: [String] = []
// 能够从 Kotlin 正确推断出 String 类型
for try await element in flowOfStrings().asAsyncSequence() {
actual.append(element)
}有关 Swift 导出的更多信息,请参阅我们的文档。
垃圾回收器中默认启用并发标记
在 Kotlin 2.0.20 中,Kotlin 团队引入了对并发标记清除垃圾回收器 (CMS GC) 的实验性支持。在处理了用户反馈并修复了回归问题后,我们现在准备从 Kotlin 2.3.20-Beta1 开始默认启用 CMS。
垃圾回收器中之前的默认并行标记并发清除 (PMCS) 设置在标记堆中的对象时必须暂停应用程序线程。相比之下,CMS 允许标记阶段与应用程序线程并发运行。
这显著改善了 GC 暂停时长和应用响应能力,这对于对延迟敏感的应用程序性能至关重要。CMS 在使用 Compose Multiplatform 构建的 UI 应用程序基准测试中已经证明了其有效性。
如果您遇到问题,可以切换回 PMCS。为此,请在您的 gradle.properties 文件中设置以下二进制选项:
kotlin.native.binary.gc=pmcs有关 Kotlin/Native 垃圾回收器的更多信息,请参阅我们的文档。
Kotlin/Wasm
Kotlin 2.3.20-Beta1 默认启用了 Kotlin/Wasm 的增量编译,并引入了对 WebAssembly 组件模型的支持。
默认启用增量编译
Kotlin/Wasm 在 2.1.0 中引入了增量编译。从 Kotlin 2.3.20-Beta1 开始,该功能已进入稳定阶段并默认启用。 通过此功能,编译器仅重新构建受最近更改影响的文件,从而显著缩短了构建时间。
要禁用增量编译,请将以下行添加到项目的 local.properties 或 gradle.properties 文件中:
# gradle.properties
kotlin.incremental.wasm=false如果您遇到任何问题,请在我们的 YouTrack 中报告。
支持 WebAssembly 组件模型
Kotlin 2.3.20-Beta1 通过引入对 WebAssembly 组件模型的实验性支持,使 Kotlin/Wasm 更进一步。该提案定义了一种通过标准化接口和类型从 Wasm 模块构建组件的方法。这种方法有助于 Wasm 从底层的二进制指令格式演变为一个用于组合可重用的、与语言无关的组件的系统。它使 Kotlin/Wasm 能够超越浏览器。例如,Kotlin 和 WebAssembly 非常适合函数即服务(FaaS)或无服务器应用。
要试用此功能,请查看使用 wasi:http 构建的简单服务器。

请在 YouTrack 中分享您的反馈。
Kotlin/JS
Kotlin 2.3.20-Beta1 增加了对将 value class 导出到 JavaScript/TypeScript 的支持,并在内联 JS 代码时支持 ES2015 功能。
支持将 value class 导出到 JavaScript/TypeScript
此前,只有常规的 Kotlin 类可以导出到 JavaScript/TypeScript。 Kotlin 2.3.20-Beta1 解除了这一限制。您现在可以将 Kotlin 的内联 value class 导出为常规的 TypeScript 类。
To export a value class, mark it with the @JsExport annotation on the Kotlin side:
// Kotlin
@JsExport
@JvmInline
value class Email(val address: String) {
init { require(address.contains("@")) { "Invalid email" } }
}
@JsExport
class AuthService {
suspend fun login(email: Email): String = ...
}在 TypeScript 端,它看起来像一个常规类:
// TypeScript
import { AuthService, Email } from "..."
const auth = new AuthService();
console.log(await auth.login(new Email("[email protected]")));
// "Welcome, [email protected]!"
console.log(await auth.login(new Email("not-an-email")));
// "Invalid email"有关更多信息,请参阅 @JsExport 注解。
内联 JS 代码时支持 ES2015 功能
从 Kotlin 2.3.20-Beta1 开始,JavaScript 代码内联已全面支持 ES2015 功能。
这对于与第三方库的互操作以及直接控制自动应用程序代码生成非常有用。
您现在可以在 js() 调用中使用现代 JS 功能,包括:
- Lambda(箭头函数)
- ES 类
- 模板字符串
- 扩展运算符
const和let变量声明- 生成器(Generators)
请记住,js() 函数的参数应为字符串常量,因为它在编译时被解析并“原样”转换为 JavaScript 代码。 例如,对于扩展运算符,请使用:
fun spreadExample(): dynamic = js("""
const add = (a, b, c) => a + b + c;
const nums = [1, 2, 3];
const sum = add(...nums);
const a = [1, 2, 3];
const b = [...a, 4, 5, 6];
return { sum, b: b };
""")有关内联 JavaScript 代码的更多信息,请参阅我们的文档。
Gradle
Kotlin 2.3.20-Beta1 与 Gradle 7.6.3 至 9.4.1 完全兼容。您也可以使用截至最新版本的 Gradle。但请注意,这样做可能会导致弃用警告,且某些新的 Gradle 功能可能无法正常工作。
Maven
Kotlin 2.3.20-Beta1 通过 Java 与 JVM 目标版本之间的自动对齐,使项目配置变得更加简单。
Java 与 JVM 目标版本之间的自动对齐
为了简化项目配置并防止兼容性问题,Kotlin Maven 插件现在会自动将 JVM 目标版本与项目中配置的 Java 编译器版本对齐。
这确保了 Kotlin 和 Maven 编译器针对相同的字节码版本,从而避免 Kotlin 生成的字节码与项目其余部分或预期的部署环境不兼容的问题。
启用 <extensions> 选项后,您不再需要 kotlin.compiler.jvmTarget 属性。如果尚未定义,Kotlin Maven 插件将按以下顺序自动解析 JVM 目标版本:
作为定义的
maven.compiler.release版本(无论是在项目属性中定义还是在maven-compiler-plugin配置中定义)。在这种情况下,Kotlin 编译器会同时设置
jvmTarget和jdkRelease编译器选项,从而将 API 限制在特定的 JDK 版本。如果未设置 Maven release 版本,则作为
maven.compiler.target版本。编译器目标版本可以在项目属性中定义,也可以在maven-compiler-plugin配置中定义。在这种情况下,仅设置 Kotlin 的
jvmTarget,且 API 不受特定 JDK 版本的限制。
这大大简化了您的 Kotlin 项目配置,因此您的 pom.xml 文件可以如下所示:
<properties>
<maven.compiler.release>17</maven.compiler.release>
<kotlin.version>2.3.0</kotlin.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<extensions>true</extensions>
</plugin>
</plugins>
</build>在构建期间,插件会输出类似的消息:
[INFO] Using jvmTarget=17 (derived from maven.compiler.release=17)
<extensions>选项仅检查项目级属性和全局maven-compiler-plugin配置。 它不会检查插件<executions>部分中定义的配置。
有关自动项目配置的更多信息,请参阅我们的文档。
Kotlin 编译器
Kotlin 2.3.20-Beta1 为 .klib 编译期间在同一模块中声明的内联函数提供了更加一致的行为。
klib 编译期间一致的模块内函数内联
此前,函数内联在不同的 Kotlin 平台上的行为不一致。JetBrains 团队正致力于在所有支持的平台上统一该行为,以确保相同的兼容性保证。
在 Kotlin/JVM 上,函数内联发生在编译时。因此,当使用 Kotlin/JVM 编译器编译 Kotlin 源代码时,生成的类文件在字节码中没有内联函数调用,因为内联函数的主体已内联到其调用站点,所以其行为在编译期间是固定的。
相反,在 Kotlin/Native、Kotlin/JS 和 Kotlin/Wasm 上,函数内联并非发生在源代码到 klib 的编译期间,而是在二进制生成期间发生。因此,内联函数的行为在 .klib 编译期间并未固定,且 .klib 库无法为内联函数提供与 Kotlin/JVM 相同的兼容性保证。
Kotlin 2.3.20-Beta1 通过在生成 .klib 构件时启用模块内内联,迈出了统一内联函数行为的第一步:
// 现有的 logging.klib 库
inline fun logDebug(message: String) {
println("[DEBUG] $message")
}// 当前编译的 App 模块
inline fun greetUser(name: String) {
println("Hello, $name!")
}
fun main() {
logDebug("App started") // 未内联:在另一个模块中声明
greetUser("Alice") // 已内联:在同一个模块中声明
}当编译为 .klib 时,代码看起来类似于:
// 伪代码
fun main() {
logDebug("App started") // 未内联,在另一个模块中声明
val tmp0 = "Alice"
println("Hello, $tmp0!") // 从 greetUser() 内联
}这意味着在 .klib 编译期间,只有在同一个模块中声明的内联函数才会被内联。在这种情况下,其他函数将在生成特定平台的二进制文件期间内联。
如何启用
从 2.3.20-Beta1 开始,对于 Kotlin/Native、Kotlin/JS 和 Kotlin/Wasm,默认启用模块内内联。
如果您遇到此功能的意外问题,可以在命令行中使用以下编译器选项将其禁用:
-Xklib-ir-inliner=disabled下一步是启用跨模块内联,以确保项目中的所有内联函数都得到一致的内联。这一更改计划在未来的 Kotlin 版本中推出,但您已经可以在命令行中使用以下编译器选项进行试用:
-Xklib-ir-inliner=full请在 YouTrack 中分享您的反馈并报告任何问题。
