本文翻译自 What's new in Kotlin 2.2.20,原文发布于 2025 年 9 月 10 日
Kotlin 2.2.20 现已发布,为 Web 开发带来了重要变更。 Kotlin/Wasm 现已进入 Beta 阶段,改进了 JavaScript 互操作中的异常处理、npm 依赖管理、内置浏览器调试支持,并为 js
和 wasmJs
目标提供了新的 共享源集。
此外,还有一些主要亮点:
- Kotlin Multiplatform:默认提供 Swift 导出、稳定的 Kotlin 库跨平台编译 以及 声明通用依赖的新方法。
- 语言:改进了将 lambda 传递给具有 suspend 函数类型的重载时的重载解析。
- Kotlin/Native:支持二进制文件中的堆栈金丝雀 和 更小的 release 二进制文件大小。
- Kotlin/JS:
Long
值编译为 JavaScriptBigInt
。
IDE 支持
支持 Kotlin 2.2.20 的 Kotlin 插件已捆绑在最新版本的 IntelliJ IDEA 和 Android Studio 中。要更新,您只需在构建脚本中将 Kotlin 版本更改为 2.2.20。
有关详细信息,请参阅 更新到新版本。
语言
在 Kotlin 2.2.20 中,您可以试用计划用于 Kotlin 2.3.0 的即将推出的语言功能,包括 改进了将 lambda 传递给具有 suspend
函数类型的重载时的重载解析 和 支持在具有显式返回类型的表达式主体中使用 return
语句。此版本还包括对 when
表达式的详尽性检查、reified Throwable
catches 和 Kotlin contracts 的改进。
改进了对带有 suspend
函数类型的 lambda 的重载解析
以前,使用常规函数类型和 suspend
函数类型重载函数会在传递 lambda 时导致歧义错误。您可以通过显式类型转换来解决此错误,但编译器会错误地报告 No cast needed
警告:
kotlin
// 定义两个重载
fun transform(block: () -> Int) {}
fun transform(block: suspend () -> Int) {}
fun test() {
// 因重载解析歧义而失败
transform({ 42 })
// 使用显式转换,但编译器错误地报告
// "No cast needed" 警告
transform({ 42 } as () -> Int)
}
通过此更改,当您同时定义常规和 suspend
函数类型重载时,没有转换的 lambda 会解析为常规重载。使用 suspend
关键字显式解析为 suspend 重载:
kotlin
// 解析为 transform(() -> Int)
transform({ 42 })
// 解析为 transform(suspend () -> Int)
transform(suspend { 42 })
此行为将在 Kotlin 2.3.0 中默认启用。要立即测试,请使用以下编译器选项将您的语言版本设置为 2.3
:
kotlin
-language-version 2.3
或者在您的 build.gradle(.kts)
文件中配置它:
kotlin
kotlin {
compilerOptions {
languageVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_3)
}
}
我们希望您能在我们的问题跟踪器 YouTrack 中提供反馈。
支持在具有显式返回类型的表达式主体中使用 return
语句
以前,在表达式主体中使用 return
会导致编译器错误,因为它可能导致函数的返回类型被推断为 Nothing
。
kotlin
fun example() = return 42
// Error: Returns are prohibited for functions with an expression body
// 错误:表达式主体的函数禁止使用 return
通过此更改,您现在可以在表达式主体中使用 return
,只要显式写入返回类型:
kotlin
// 显式指定返回类型
fun getDisplayNameOrDefault(userId: String?): String = getDisplayName(userId ?: return "default")
// 失败,因为它没有显式指定返回类型
fun getDisplayNameOrDefault(userId: String?) = getDisplayName(userId ?: return "default")
同样,具有表达式主体的函数中 lambda 和嵌套表达式内的 return
语句过去会无意中编译。只要显式指定返回类型,Kotlin 现在支持这些情况。没有显式返回类型的情况将在 Kotlin 2.3.0 中被弃用:
kotlin
// 返回类型未显式指定,并且 return 语句在 lambda 内部
// 这将被弃用
fun returnInsideLambda() = run { return 42 }
// 返回类型未显式指定,并且 return 语句在
// 局部变量的初始化器中,将被弃用
fun returnInsideIf() = when {
else -> {
val result = if (someCondition()) return "" else "value"
result
}
}
此行为将在 Kotlin 2.3.0 中默认启用。要立即测试,请使用以下编译器选项将您的语言版本设置为 2.3
:
kotlin
-language-version 2.3
或者在您的 build.gradle(.kts)
文件中配置它:
kotlin
kotlin {
compilerOptions {
languageVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_3)
}
}
我们希望您能在我们的问题跟踪器 YouTrack 中提供反馈。
基于数据流的 when
表达式详尽性检查
Kotlin 2.2.20 引入了基于数据流的 when
表达式详尽性检查。以前,编译器的检查仅限于 when
表达式本身,通常会强制您添加多余的 else
分支。通过此更新,编译器现在会跟踪先前的条件检查和提前返回,因此您可以删除多余的 else
分支。
例如,编译器现在认识到当满足 if
条件时函数会返回,因此 when
表达式只需要处理其余情况:
kotlin
enum class UserRole { ADMIN, MEMBER, GUEST }
fun getPermissionLevel(role: UserRole): Int {
// 在 when 表达式之外涵盖 Admin 情况
if (role == UserRole.ADMIN) return 99
return when (role) {
UserRole.MEMBER -> 10
UserRole.GUEST -> 1
// 您不再需要包含此 else 分支
// else -> throw IllegalStateException()
}
}
此功能是 Experimental。要启用它,请将以下编译器选项添加到您的 build.gradle(.kts)
文件中:
kotlin
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xdata-flow-based-exhaustiveness")
}
}
支持在 catch
子句中使用 reified 类型
在 Kotlin 2.2.20 中,编译器现在允许在 inline
函数的 catch
子句中使用 reified 泛型类型参数。
这是一个例子:
kotlin
inline fun <reified ExceptionType : Throwable> handleException(block: () -> Unit) {
try {
block()
// 更改后现在允许这样做
} catch (e: ExceptionType) {
println("Caught specific exception: ${e::class.simpleName}")
}
}
fun main() {
// 尝试执行可能抛出 IOException 的操作
handleException<java.io.IOException> {
throw java.io.IOException("File not found")
}
// Caught specific exception: IOException
}
以前,尝试在 inline
函数中捕获 reified Throwable
类型会导致错误。
此行为将在 Kotlin 2.4.0 中默认启用。要立即使用,请将以下编译器选项添加到您的 build.gradle(.kts)
文件中:
kotlin
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xallow-reified-type-in-catch")
}
}
Kotlin 团队感谢外部贡献者 Iven Krall 的贡献。
改进的 Kotlin contracts
Kotlin 2.2.20 对 Kotlin contracts 进行了多项改进,包括:
- 支持在 contract 类型断言中使用泛型。
- 支持在属性访问器和特定运算符函数中使用 contracts。
- 支持在 contracts 中使用
returnsNotNull()
函数作为在满足条件时确保非空返回值的 - 新的
holdsIn
关键字,允许您在 lambda 内部传递时假定条件为真。
这些改进是 Experimental。要选择加入,您仍然需要在声明 contracts 时使用 @OptIn(ExperimentalContracts::class)
注解。holdsIn
关键字和 returnsNotNull()
函数也需要 @OptIn(ExperimentalExtendedContracts::class)
注解。
要使用这些改进,您还需要添加下面每个部分中描述的编译器选项。
我们希望您能在我们的 问题跟踪器 中提供反馈。
支持在 contract 类型断言中使用泛型
您现在可以编写对泛型类型执行类型断言的 contracts:
kotlin
import kotlin.contracts.*
sealed class Failure {
class HttpError(val code: Int) : Failure()
// 在此处插入其他失败类型
}
sealed class Result<out T, out F : Failure> {
class Success<T>(val data: T) : Result<T, Nothing>()
class Failed<F : Failure>(val failure: F) : Result<Nothing, F>()
}
@OptIn(ExperimentalContracts::class)
// 使用 contract 对泛型类型进行断言
fun <T, F : Failure> Result<T, F>.isHttpError(): Boolean {
contract {
returns(true) implies (this@isHttpError is Result.Failed<Failure.HttpError>)
}
return this is Result.Failed && this.failure is Failure.HttpError
}
在此示例中,contract 对 Result
对象执行类型断言,允许编译器安全地将其 智能转换 为断言的泛型类型。
此功能是 Experimental。要选择加入,请将以下编译器选项添加到您的 build.gradle(.kts)
文件中:
kotlin
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xallow-contracts-on-more-functions")
}
}
支持在属性访问器和特定运算符函数中使用 contracts
您现在可以在属性访问器和特定运算符函数中定义 contracts。这使您可以在更多类型的声明上使用 contracts,使其更加灵活。
例如,您可以在 getter 中使用 contract 来为接收者对象启用智能转换:
kotlin
import kotlin.contracts.*
val Any.isHelloString: Boolean
get() {
@OptIn(ExperimentalContracts::class)
// 当 getter 返回 true 时,启用将接收者智能转换为 String
contract { returns(true) implies (this@isHelloString is String) }
return "hello" == this
}
fun printIfHelloString(x: Any) {
if (x.isHelloString) {
// 在将接收者智能转换为 String 后打印长度
println(x.length)
// 5
}
}
此外,您可以在以下运算符函数中使用 contracts:
invoke
contains
rangeTo
、rangeUntil
componentN
iterator
unaryPlus
、unaryMinus
、not
inc
、dec
这是一个在运算符函数中使用 contract 以确保在 lambda 内部初始化变量的示例:
kotlin
import kotlin.contracts.*
class Runner {
@OptIn(ExperimentalContracts::class)
// 启用在 lambda 内部赋值的变量的初始化
operator fun invoke(block: () -> Unit) {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
}
}
fun testOperator(runner: Runner) {
val number: Int
runner {
number = 1
}
// 在 contract 保证确定初始化后打印值
println(number)
// 1
}
此功能是 Experimental。要选择加入,请将以下编译器选项添加到您的 build.gradle(.kts)
文件中:
kotlin
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xallow-contracts-on-more-functions")
}
}
支持在 contracts 中使用 returnsNotNull()
函数
Kotlin 2.2.20 引入了用于 contracts 的 returnsNotNull()
函数。您可以使用此函数确保在满足特定条件时函数返回非空值。这通过用一个简洁的函数替换单独的可空和不可空函数重载来简化您的代码:
kotlin
import kotlin.contracts.*
@OptIn(ExperimentalContracts::class, ExperimentalExtendedContracts::class)
fun decode(encoded: String?): String? {
contract {
// 当输入为非空时保证非空返回值
(encoded != null) implies (returnsNotNull())
}
if (encoded == null) return null
return java.net.URLDecoder.decode(encoded, "UTF-8")
}
fun useDecodedValue(s: String?) {
// 使用安全调用,因为返回值可能为 null
decode(s)?.length
if (s != null) {
// 在智能转换后将返回值视为非空
decode(s).length
}
}
在此示例中,decode()
函数中的 contract 允许编译器在输入为非空时智能转换其返回值,从而无需额外的空检查或多个重载。
此功能是 Experimental。要选择加入,请将以下编译器选项添加到您的 build.gradle(.kts)
文件中:
kotlin
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xallow-condition-implies-returns-contracts")
}
}
新的 holdsIn
关键字
Kotlin 2.2.20 引入了用于 contracts 的新 holdsIn
关键字。您可以使用它来确保在特定 lambda 内部假定布尔条件为 true
。这使您可以使用 contracts 构建具有条件智能转换的 DSL。
这是一个例子:
kotlin
import kotlin.contracts.*
@OptIn(ExperimentalContracts::class, ExperimentalExtendedContracts::class)
fun <T> T.alsoIf(condition: Boolean, block: (T) -> Unit): T {
contract {
// 声明 lambda 最多运行一次
callsInPlace(block, InvocationKind.AT_MOST_ONCE)
// 声明在 lambda 内部假定条件为真
condition holdsIn block
}
if (condition) block(this)
return this
}
fun useApplyIf(input: Any) {
val result = listOf(1, 2, 3)
.first()
.alsoIf(input is Int) {
// 输入参数在 lambda 内部被智能转换为 Int
// 打印输入和第一个列表元素的和
println(input + it)
// 2
}
.toString()
}
此功能是 Experimental。要选择加入,请将以下编译器选项添加到您的 build.gradle(.kts)
文件中:
kotlin
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xallow-holdsin-contract")
}
}
Kotlin/JVM:支持 invokedynamic
和 when
表达式
在 Kotlin 2.2.20 中,您现在可以使用 invokedynamic
编译 when
表达式。以前,具有多个类型检查的 when
表达式会编译为字节码中一长串的 instanceof
检查。
现在,当满足以下条件时,您可以将 invokedynamic
与 when
表达式一起使用,以生成更小的字节码,类似于 Java switch
语句生成的字节码:
- 除
else
之外的所有条件都是is
或null
检查。 - 表达式不包含 守卫条件 (
if
)。 - 条件不包括不能直接进行类型检查的类型,例如可变的 Kotlin 集合 (
MutableList
) 或函数类型 (kotlin.Function1
、kotlin.Function2
等)。 - 除
else
外至少有两个条件。 - 所有分支都检查
when
表达式的相同主题。
例如:
kotlin
open class Example
class A : Example()
class B : Example()
class C : Example()
fun test(e: Example) = when (e) {
// 使用 invokedynamic 和 SwitchBootstraps.typeSwitch
is A -> 1
is B -> 2
is C -> 3
else -> 0
}
启用新功能后,此示例中的 when
表达式会编译为单个 invokedynamic
类型切换,而不是多个 instanceof
检查。
要启用此功能,请使用 JVM 目标 21 或更高版本编译您的 Kotlin 代码,并添加以下编译器选项:
bash
-Xwhen-expressions=indy
或者将其添加到您的 build.gradle(.kts)
文件的 compilerOptions {}
块中:
kotlin
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xwhen-expressions=indy")
}
}
此功能是 Experimental。我们希望您能在我们的问题跟踪器 YouTrack 中提供反馈。
Kotlin Multiplatform
Kotlin 2.2.20 为 Kotlin Multiplatform 带来了重大变化:Swift 导出默认可用,有一个新的共享源集,您可以尝试一种管理通用依赖的新方法。
Swift 导出默认可用
Kotlin 2.2.20 引入了对 Swift 导出的实验性支持。它允许您直接导出 Kotlin 源码并从 Swift 中以惯用的方式调用 Kotlin 代码,从而无需 Objective-C 头文件。
这应该会显着改善 Apple 目标的多平台开发。例如,如果您有一个带有顶级函数的 Kotlin 模块,Swift 导出可以实现干净的、特定于模块的导入,从而消除令人困惑的 Objective-C 下划线和混乱的名称。
主要功能是:
- 多模块支持。每个 Kotlin 模块都作为单独的 Swift 模块导出,从而简化了函数调用。
- 包支持。Kotlin 包在导出期间被明确保留,避免了在生成的 Swift 代码中出现命名冲突。
- 类型别名。Kotlin 类型别名在 Swift 中被导出和保留,从而提高了可读性。
- 增强了基元类型的可空性。与 Objective-C 互操作不同,后者需要将像
Int?
这样的类型装箱到像KotlinInt
这样的包装类中以保留可空性,Swift 导出直接转换可空性信息。 - 重载。您可以在 Swift 中调用 Kotlin 的重载函数而不会产生歧义。
- 扁平化的包结构。您可以将 Kotlin 包转换为 Swift 枚举,从而从生成的 Swift 代码中删除包前缀。
- 模块名称自定义。您可以在 Kotlin 项目的 Gradle 配置中自定义生成的 Swift 模块名称。
如何启用 Swift 导出
该功能目前是 Experimental,并且仅在使用直接集成 将 iOS 框架连接到 Xcode 项目的项目中有效。这是使用 IntelliJ IDEA 中的 Kotlin Multiplatform 插件或通过 Web向导 创建的多平台项目的标准配置。
要试用 Swift 导出,请配置您的 Xcode 项目:
- 在 Xcode 中,打开项目设置。
- 在 Build Phases 选项卡上,找到带有
embedAndSignAppleFrameworkForXcode
任务的 Run Script 阶段。 - 调整脚本以在运行脚本阶段使用
embedSwiftExportForXcode
任务:
bash
./gradlew :<Shared module name>:embedSwiftExportForXcode

- 构建项目。Swift 模块在构建输出目录中生成。
该功能默认可用。如果您在以前的版本中已经启用了它,现在可以从您的 gradle.properties
文件中删除 kotlin.experimental.swift-export.enabled
。
为了节省时间,请克隆我们已经设置好 Swift 导出的 公共示例。
有关 Swift 导出的更多信息,请参阅我们的 文档。
留下反馈
我们计划在未来的 Kotlin 版本中扩展并逐步稳定 Swift 导出支持。在 Kotlin 2.2.20 之后,我们将专注于改善 Kotlin 和 Swift 之间的互操作性,尤其是在协程和流方面。
支持 Swift 导出是 Kotlin Multiplatform 的一个重大变化。我们希望您能提供反馈:
- 直接在 Kotlin Slack 中联系开发团队 -- 获取邀请 并加入 #swift-export 频道。
- 在 YouTrack 中报告您遇到的任何 Swift 导出问题。
js
和 wasmJs
目标的共享源集
以前,Kotlin Multiplatform 默认不包含 JavaScript (js
) 和 WebAssembly (wasmJs
) Web 目标的共享源集。要在 js
和 wasmJs
之间共享代码,您必须手动配置自定义源集或在两个地方编写代码,一个版本用于 js
,另一个用于 wasmJs
。例如:
kotlin
// commonMain
expect suspend fun readCopiedText(): String
// jsMain
external interface Navigator { val clipboard: Clipboard }
// JS 和 Wasm 中不同的互操作
external interface Clipboard { fun readText(): Promise<String> }
external val navigator: Navigator
suspend fun readCopiedText(): String {
// JS 和 Wasm 中不同的互操作
return navigator.clipboard.readText().await()
}
// wasmJsMain
external interface Navigator { val clipboard: Clipboard }
external interface Clipboard { fun readText(): Promise<JsString> }
external val navigator: Navigator
suspend fun readCopiedText(): String {
return navigator.clipboard.readText().await().toString()
}
从这个版本开始,当您使用 默认层次结构模板 时,Kotlin Gradle 插件会为 Web 添加一个新的共享源集(包括 webMain
和 webTest
)。
通过此更改,web
源集成为 js
和 wasmJs
源集的父级。更新后的源集层次结构如下所示:

新的源集允许您为 js
和 wasmJs
目标编写一份代码。您可以将共享代码放在 webMain
中,它会自动为两者工作:
kotlin
// commonMain
expect suspend fun readCopiedText(): String
// webMain
external interface Navigator { val clipboard: Clipboard }
external interface Clipboard { fun readText(): Promise<JsString> }
external val navigator: Navigator
actual suspend fun readCopiedText(): String {
return navigator.clipboard.readText().await().toString()
}
此更新简化了 js
和 wasmJs
目标之间的代码共享。它在两种情况下特别有用:
- 如果您是库作者,并且希望在不重复代码的情况下为
js
和wasmJs
目标添加支持。 - 如果您正在开发针对 Web 的 Compose Multiplatform 应用程序,为
js
和wasmJs
目标启用交叉编译以获得更广泛的浏览器兼容性。鉴于这种回退模式,当您创建网站时,它可以在所有浏览器上开箱即用,因为现代浏览器使用wasmJs
,而旧浏览器使用js
。
要试用此功能,请在您的 build.gradle(.kts)
文件的 kotlin {}
块中使用 默认层次结构模板:
kotlin
kotlin {
js()
wasmJs()
// 启用默认源集层次结构,包括 webMain 和 webTest
applyDefaultHierarchyTemplate()
}
在使用默认层次结构之前,请仔细考虑任何潜在的冲突,如果您的项目具有自定义共享源集,或者您已重命名 js("web")
目标。要解决这些冲突,请重命名冲突的源集或目标,或者不要使用默认层次结构。
稳定的 Kotlin 库跨平台编译
Kotlin 2.2.20 完成了一个重要的 路线图项目,稳定了 Kotlin 库的跨平台编译。
您现在可以使用任何主机生成用于发布 Kotlin 库的 .klib
工件。这大大简化了发布过程,特别是对于以前需要 Mac 机器的 Apple 目标。
该功能默认可用。如果您已经使用 kotlin.native.enableKlibsCrossCompilation=true
启用了交叉编译,现在可以从您的 gradle.properties
文件中删除它。
不幸的是,仍然存在一些限制。如果您有以下情况,您仍然需要使用 Mac 机器:
- 您的库或任何依赖模块具有 cinterop 依赖项。
- 您在项目中设置了 CocoaPods 集成。
- 您需要为 Apple 目标构建或测试 最终二进制文件。
有关多平台库发布的更多信息,请参阅我们的 文档。
声明通用依赖的新方法
为了简化使用 Gradle 设置多平台项目,当您的项目使用 Gradle 8.8 或更高版本时,Kotlin 2.2.20 现在允许您通过使用顶层 dependencies {}
块在 kotlin {}
块中声明通用依赖。这些依赖的行为就像它们在 commonMain
源集中声明一样。此功能类似于您用于 Kotlin/JVM 和仅 Android 项目的依赖块,现在在 Kotlin Multiplatform 中是 Experimental。
在项目级别声明通用依赖可以减少跨源集的重复配置,并有助于简化您的构建设置。您仍然可以根据需要在每个源集中添加特定于平台的依赖。
要试用此功能,请通过在顶层 dependencies {}
块之前添加 @OptIn(ExperimentalKotlinGradlePluginApi::class)
注解来选择加入。例如:
kotlin
kotlin {
@OptIn(ExperimentalKotlinGradlePluginApi::class)
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
}
}
我们希望您能在 YouTrack 中提供有关此功能的反馈。
依赖中目标支持的新诊断
在 Kotlin 2.2.20 之前,如果您的构建脚本中的依赖不支持源集所需的所有目标,Gradle 生成的错误消息很难理解问题所在。
Kotlin 2.2.20 引入了一种新的诊断,可以清楚地显示每个依赖支持哪些目标,不支持哪些目标。
此诊断默认启用。如果由于某种原因您需要禁用它,请在此 YouTrack 问题 的评论中告诉我们。您可以使用以下 Gradle 属性在您的 gradle.properties
文件中禁用诊断:
属性 | 描述 |
---|---|
kotlin.kmp.eagerUnresolvedDependenciesDiagnostic=false |
仅对元数据编译和导入运行诊断 |
kotlin.kmp.unresolvedDependenciesDiagnostic=false |
完全禁用诊断 |
Kotlin/Native
Kotlin 2.2.20 改进了与 Objective-C/Swift 的互操作性、调试和新的二进制选项。
支持二进制文件中的堆栈金丝雀
译注:堆栈金丝雀(Stack Canary)是一种安全机制,用于保护堆栈溢出攻击。它会在初始化一个栈帧时,在栈底设置一个随机的canary值,栈帧销毁前测试该值是否"死掉"(即是否被改变),若被改变则说明栈溢出发生,程序走另一个流程结束,以免漏洞利用成功。
从 Kotlin 2.2.20 开始,Kotlin 在生成的 Kotlin/Native 二进制文件中增加了对堆栈金丝雀的支持。作为堆栈保护的一部分,此安全功能可防止堆栈粉碎,从而缓解一些常见的应用程序漏洞。此功能已在 Swift 和 Objective-C 中提供,现在 Kotlin 也支持它。
Kotlin/Native 中堆栈保护的实现遵循 Clang 中堆栈保护器的行为。
要启用堆栈金丝雀,请将以下 二进制选项 添加到您的 gradle.properties
文件中:
none
kotlin.native.binary.stackProtector=yes
该属性为所有易受堆栈粉碎攻击的 Kotlin 函数启用该功能。替代模式是:
kotlin.native.binary.stackProtector=strong
,它对易受堆栈粉碎攻击的函数使用更强的启发式方法。kotlin.native.binary.stackProtector=all
,它为所有函数启用堆栈保护器。
请注意,在某些情况下,堆栈保护可能会带来性能成本。
更小的 release 二进制文件大小
Kotlin 2.2.20 引入了 smallBinary
选项,可以帮助您减小 release 二进制文件的大小。新选项有效地将 -Oz
设置为 LLVM 编译阶段编译器的默认优化参数。
启用 smallBinary
选项后,您可以使 release 二进制文件更小并缩短构建时间。但是,在某些情况下,它可能会影响运行时性能。
新功能目前是 Experimental。要在您的项目中试用,请将以下 二进制选项 添加到您的 gradle.properties
文件中:
none
kotlin.native.binary.smallBinary=true
Kotlin 团队感谢 Troels Lund 在实现此功能方面的帮助。
改进的调试器对象摘要
Kotlin/Native 现在为 LLDB 和 GDB 等调试器工具生成更清晰的对象摘要。这提高了生成的调试信息的可读性,并简化了您的调试体验。
例如,考虑以下对象:
kotlin
class Point(val x: Int, val y: Int)
val point = Point(1, 2)
以前,检查只会显示有限的信息,包括指向对象内存地址的指针:
none
(lldb) v point
(ObjHeader *) point = [x: ..., y: ...]
(lldb) v point->x
(int32_t *) x = 0x0000000100274048
使用 Kotlin 2.2.20,调试器现在显示更丰富的详细信息,包括实际值:
none
(lldb) v point
(ObjHeader *) point = Point(x=1, y=2)
(lldb) v point->x
(int32_t) point->x = 1
Kotlin 团队感谢 Nikita Nazarov 在实现此功能方面的帮助。
有关 Kotlin/Native 调试的更多信息,请参阅 文档。
Objective-C 头文件中块类型的显式名称
Kotlin 2.2.20 引入了一个选项,可以为从 Kotlin/Native 项目导出的 Objective-C 头文件中的 Kotlin 函数类型添加显式参数名称。参数名称改进了 Xcode 中的自动完成建议,并有助于避免 Clang 警告。
以前,块类型中的参数名称在生成的 Objective-C 头文件中被省略。在这种情况下,Xcode 的自动完成会建议在 Objective-C 块中调用此类函数时不带参数名称。生成的块会触发 Clang 警告。
例如,对于以下 Kotlin 代码:
kotlin
// Kotlin:
fun greetUser(block: (name: String) -> Unit) = block("John")
生成的 Objective-C 头文件没有参数名称:
objectivec
// Objective-C:
+ (void)greetUserBlock:(void (^)(NSString *))block __attribute__((swift_name("greetUser(block:)")));
因此,当在 Xcode 中从 Objective-C 调用 greetUserBlock()
函数时,IDE 建议:
objectivec
// Objective-C:
greetUserBlock:^(NSString *) {
// ...
};
建议中缺少的参数名称 (NSString *)
会导致 Clang 警告。
使用新选项,Kotlin 将参数名称从 Kotlin 函数类型转发到 Objective-C 块类型,因此 Xcode 在建议中使用它们:
objectivec
// Objective-C:
greetUserBlock:^(NSString *name) {
// ...
};
要启用显式参数名称,请将以下 二进制选项 添加到您的 gradle.properties
文件中:
none
kotlin.native.binary.objcExportBlockExplicitParameterNames=true
Kotlin 团队感谢 Yijie Jiang 实现此功能。
减小 Kotlin/Native 发行版的大小
Kotlin/Native 发行版过去包含两个带有编译器代码的 JAR 文件:
konan/lib/kotlin-native.jar
konan/lib/kotlin-native-compiler-embeddable.jar
从 Kotlin 2.2.20 开始,不再发布 kotlin-native.jar
。
删除的 JAR 文件是可嵌入编译器的旧版本,不再需要。此更改显着减小了发行版的大小。
因此,以下选项现在已弃用并删除:
kotlin.native.useEmbeddableCompilerJar=false
Gradle 属性。相反,可嵌入编译器 JAR 文件始终用于 Kotlin/Native 项目。KotlinCompilerPluginSupportPlugin.getPluginArtifactForNative()
函数。相反,始终使用getPluginArtifact()
函数。
有关更多信息,请参阅 YouTrack 问题。
默认将 KDocs 导出到 Objective-C 头文件
在编译 Kotlin/Native 最终二进制文件期间,KDoc 注释现在默认导出到生成的 Objective-C 头文件中。
以前,您需要手动将 -Xexport-kdoc
选项添加到您的构建文件中。现在,它会自动传递给编译任务。
此选项将 KDoc 注释嵌入到 klibs 中,并在生成 Apple 框架时从 klibs 中提取注释。因此,类和方法上的注释会在自动完成期间出现,例如,在 Xcode 中。
您可以在您的 build.gradle(.kts)
文件的 binaries {}
块中禁用从 klibs 导出 KDoc 注释到生成的 Apple 框架:
kotlin
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
kotlin {
iosArm64 {
binaries {
framework {
baseName = "sdk"
@OptIn(ExperimentalKotlinGradlePluginApi::class)
exportKdoc.set(false)
}
}
}
}
有关更多信息,请参阅 我们的文档。
弃用 x86_64
Apple 目标
Apple 几年前停止生产带有 Intel 芯片的设备,并且 最近宣布 macOS Tahoe 26 将是最后一个支持基于 Intel 架构的操作系统版本。
这使得我们越来越难以在我们的构建代理上正确测试这些目标,尤其是在未来的 Kotlin 版本中,我们将更新与 macOS 26 一起提供的受支持的 Xcode 版本。
从 Kotlin 2.2.20 开始,macosX64
和 iosX64
目标被降级为支持级别 2。这意味着目标在 CI 上定期测试以确保它能编译,但可能不会自动测试以确保它能运行。
我们计划在 Kotlin 2.2.20-2.4.0 发布周期内逐步弃用所有 x86_64
Apple 目标,并最终取消对它们的支持。这包括以下目标:
macosX64
iosX64
tvosX64
watchosX64
有关支持级别的更多信息,请参阅 Kotlin/Native 目标支持。
Kotlin/Wasm
Kotlin/Wasm 现在处于 Beta 阶段,提供更高的稳定性以及改进,例如分离的 npm 依赖、改进的 JavaScript 互操作异常处理、内置浏览器调试支持 等。
分离的 npm 依赖
以前,在您的 Kotlin/Wasm 项目中,所有 npm 依赖都一起安装在您的项目文件夹中,包括 Kotlin 工具依赖和您自己的依赖。它们也一起记录在您项目的锁定文件(package-lock.json
或 yarn.lock
)中。
因此,每当 Kotlin 工具依赖更新时,即使您没有添加或更改任何内容,也必须更新您的锁定文件。
从 Kotlin 2.2.20 开始,Kotlin 工具 npm 依赖安装在您的项目之外。现在,工具和您的(用户)依赖有单独的目录:
- 工具依赖目录:
<kotlin-user-home>/kotlin-npm-tooling/<yarn|npm>/hash/node_modules
- 用户依赖目录:
build/wasm/node_modules
此外,项目目录内的锁定文件仅包含用户定义的依赖。
此改进使您的锁定文件仅关注您自己的依赖,有助于保持项目更清洁,并减少对文件的不必要更改。
此更改默认对 wasm-js
目标启用。该更改尚未对 js
目标实现。虽然有计划在未来的版本中实现它,但在 Kotlin 2.2.20 中,js
目标的 npm 依赖的行为与以前相同。
改进的 Kotlin/Wasm 和 JavaScript 互操作中的异常处理
以前,Kotlin 难以理解在 JavaScript (JS) 中抛出并跨越到 Kotlin/Wasm 代码的异常(错误)。
在某些情况下,问题也发生在相反的方向,当异常从 Wasm 代码抛出或传递到 JS 并被包装到 WebAssembly.Exception
中而没有任何详细信息时。这些 Kotlin 异常处理问题使得调试变得困难。
从 Kotlin 2.2.20 开始,异常的开发人员体验在两个方向上都得到了改善:
- 当从 JS 抛出异常时,您可以在 Kotlin 端看到更多信息。当此类异常通过 Kotlin 传播回 JS 时,它不再被包装到 WebAssembly 中。
- 当从 Kotlin 抛出异常时,它们现在可以在 JS 端作为 JS 错误被捕获。
新的异常处理在支持 WebAssembly.JSTag
功能的现代浏览器中自动工作:
- Chrome 115+
- Firefox 129+
- Safari 18.4+
在旧版浏览器中,异常处理行为保持不变。
无需配置即可支持在浏览器中调试
以前,浏览器无法自动访问调试所需的 Kotlin/Wasm 项目源。要在浏览器中调试 Kotlin/Wasm 应用程序,您必须手动配置您的构建以提供这些源,方法是将以下代码段添加到您的 build.gradle(.kts)
文件中:
kotlin
devServer = (devServer ?: KotlinWebpackConfig.DevServer()).apply {
static = (static ?: mutableListOf()).apply {
add(project.rootDir.path)
}
}
从 Kotlin 2.2.20 开始,在 现代浏览器 中调试您的应用程序可以开箱即用。当您运行 Gradle 开发任务 (*DevRun
) 时,Kotlin 会自动为浏览器提供源文件,允许您设置断点、检查变量和单步执行 Kotlin 代码,而无需额外设置。
此更改通过消除手动配置的需要简化了调试。所需的配置现在包含在 Kotlin Gradle 插件中。如果您以前已将此配置添加到您的 build.gradle(.kts)
文件中,则应将其删除以避免冲突。
在浏览器中调试默认对所有 Gradle *DevRun
任务启用。这些任务不仅提供应用程序,还提供其源文件,因此仅将其用于本地开发,并避免在源文件将被公开暴露的云或生产环境中运行它们。
处理调试期间的重复重新加载
默认提供源文件可能会导致 在 Kotlin 编译和捆绑完成之前在浏览器中重复重新加载应用程序。作为一种变通方法,请调整您的 webpack 配置以忽略 Kotlin 源文件并禁用对所提供静态文件的监视。将一个包含以下内容的 .js
文件添加到您项目根目录的 webpack.config.d
目录中:
kotlin
config.watchOptions = config.watchOptions || {
ignored: ["**/*.kt", "**/node_modules"]
}
if (config.devServer) {
config.devServer.static = config.devServer.static.map(file => {
if (typeof file === "string") {
return { directory: file,
watch: false,
}
} else {
return file
}
})
}
消除空的 yarn.lock
文件
以前,Kotlin Gradle 插件 (KGP) 会自动生成一个 yarn.lock
文件,其中包含有关 Kotlin 工具链所需的 npm 包的信息,以及项目或使用的库中任何现有的 npm 依赖。
现在,KGP 单独管理工具链依赖,并且不再生成项目级别的 yarn.lock
文件,除非项目具有 npm 依赖。
当添加 npm 依赖时,KGP 会自动创建一个 yarn.lock
文件,当删除 npm 依赖时,它会删除 yarn.lock
文件。
此更改清理了项目结构,并使其更容易跟踪何时引入了实际的 npm 依赖。
无需额外的步骤来配置此行为。从 Kotlin 2.2.20 开始,它在 Kotlin/Wasm 项目中默认应用。
完全限定类名中的新编译器错误
在 Kotlin/Wasm 上,编译器默认不会在生成的二进制文件中存储类的完全限定名称 (FQN)。这种方法避免了增加应用程序的大小。
因此,在以前的 Kotlin 版本中,调用 KClass::qualifiedName
属性会返回一个空字符串,而不是类的限定名称。
从 Kotlin 2.2.20 开始,除非您明确启用限定名称功能,否则当您在 Kotlin/Wasm 项目中使用 KClass::qualifiedName
属性时,编译器会报告错误。
此更改可防止在调用 qualifiedName
属性时出现意外的空字符串,并通过在编译时捕获问题来改善开发人员体验。
诊断默认启用,并自动报告错误。要禁用诊断并允许在 Kotlin/Wasm 中存储 FQN,请通过将以下选项添加到您的 build.gradle(.kts)
文件中,指示编译器为所有类存储完全限定名称:
kotlin
kotlin {
wasmJs {
...
compilerOptions {
freeCompilerArgs.add("-Xwasm-kclass-fqn")
}
}
}
请记住,启用此选项会增加应用程序的大小。
Kotlin/JS
Kotlin 2.2.20 支持使用 BigInt
类型表示 Kotlin 的 Long
类型,从而在导出的声明中启用 Long
。此外,此版本添加了一个 DSL 函数来清理 Node.js 参数。
使用 BigInt
类型表示 Kotlin 的 Long
类型
在 ES2020 标准之前,JavaScript (JS) 不支持精确大于 53 位的整数的基元类型。
因此,Kotlin/JS 过去将 Long
值(64 位宽)表示为包含两个 number
属性的 JavaScript 对象。这种自定义实现使 Kotlin 和 JavaScript 之间的互操作性更加复杂。
从 Kotlin 2.2.20 开始,在编译为现代 JavaScript (ES2020) 时,Kotlin/JS 现在使用 JavaScript 的内置 BigInt
类型来表示 Kotlin 的 Long
值。
此更改启用了 将 Long
类型导出到 JavaScript,这也是在 Kotlin 2.2.20 中引入的一项功能。因此,此更改简化了 Kotlin 和 JavaScript 之间的互操作性。
要启用它,您需要将以下编译器选项添加到您的 build.gradle(.kts)
文件中:
kotlin
kotlin {
js {
...
compilerOptions {
freeCompilerArgs.add("-Xes-long-as-bigint")
}
}
}
此功能是 Experimental。我们希望您能在我们的问题跟踪器 YouTrack 中提供反馈。
在导出的声明中使用 Long
由于 Kotlin/JS 使用自定义的 Long
表示,因此很难提供一种直接从 JavaScript 与 Kotlin 的 Long
交互的方法。因此,您无法将使用 Long
类型的 Kotlin 代码导出到 JavaScript。此问题影响任何使用 Long
的代码,例如函数参数、类属性或构造函数。
既然 Kotlin 的 Long
类型可以编译为 JavaScript 的 BigInt
类型,Kotlin/JS 支持将 Long
值导出到 JavaScript,从而简化了 Kotlin 和 JavaScript 代码之间的互操作性。
要启用此功能:
-
通过将以下编译器选项添加到您的
build.gradle(.kts)
文件中的freeCompilerArgs
属性,允许在 Kotlin/JS 中导出Long
:kotlinkotlin { js { ... compilerOptions { freeCompilerArgs.add("-XXLanguage:+JsAllowLongInExportedDeclarations") } } }
-
启用
BigInt
类型。请参阅 使用BigInt
类型表示 Kotlin 的Long
类型 中如何启用它。
用于更清晰参数的新 DSL 函数
在使用 Node.js 运行 Kotlin/JS 应用程序时,传递给您程序的参数 (args
) 过去包括:
- 可执行文件
Node
的路径。 - 您的脚本的路径。
- 您提供的实际命令行参数。
但是,args
的预期行为是仅包括命令行参数。为了实现这一点,您必须在您的 build.gradle(.kts)
文件或您的 Kotlin 代码中使用 drop()
函数手动跳过前两个参数:
kotlin
fun main(args: Array<String>) {
println(args.drop(2).joinToString(", "))
}
这种变通方法是重复的、容易出错的,并且在平台之间共享代码时效果不佳。
为了解决此问题,Kotlin 2.2.20 引入了一个名为 passCliArgumentsToMainFunction()
的新 DSL 函数。
使用此函数,仅包括命令行参数,而 Node
和脚本路径被排除:
kotlin
fun main(args: Array<String>) {
// 无需 drop(),只包括您的自定义参数
println(args.joinToString(", "))
}
此更改减少了样板代码,防止了因手动删除参数而导致的错误,并提高了跨平台兼容性。
要启用此功能,请在您的 build.gradle(.kts)
文件中添加以下 DSL 函数:
kotlin
kotlin {
js {
nodejs {
passCliArgumentsToMainFunction()
}
}
}
Gradle
Kotlin 2.2.20 在 Gradle 构建报告中为 Kotlin/Native 任务添加了新的编译器性能指标,并在增量编译方面进行了生活质量改进。
Gradle 构建报告中 Kotlin/Native 任务的新编译器性能指标
在 Kotlin 1.7.0 中,我们引入了 构建报告 来帮助跟踪编译器性能。从那时起,我们添加了更多指标,使这些报告更加详细和有用,以调查性能问题。
在 Kotlin 2.2.20 中,构建报告现在包括 Kotlin/Native 任务的编译器性能指标。
要了解有关构建报告以及如何配置它们的更多信息,请参阅 启用构建报告。
预览改进的 Kotlin/JVM 增量编译
Kotlin 2.0.0 引入了带有优化前端的新 K2 编译器。Kotlin 2.2.20 在此基础上,使用新的前端来提高某些复杂的 Kotlin/JVM 增量编译场景的性能。
在我们努力稳定行为的同时,这些改进默认是禁用的。要启用它们,请在您的 gradle.properties
文件中添加以下属性:
none
kotlin.incremental.jvm.fir=true
目前,kapt
编译器插件 与这种新行为不兼容。我们正在努力在未来的 Kotlin 版本中添加支持。
我们希望您能在 YouTrack 中提供有关此功能的反馈。
增量编译检测内联函数 lambda 的变化
在 Kotlin 2.2.20 之前,如果您启用增量编译并更改内联函数中 lambda 内部的逻辑,编译器不会重新编译其他模块中该内联函数的调用点。因此,这些调用点会使用 lambda 的先前版本,这可能会导致意外行为。
在 Kotlin 2.2.20 中,编译器现在会检测内联函数 lambda 的变化,并自动重新编译其调用点。
Maven:kotlin-maven-plugin
中对 Kotlin 守护进程的支持
Kotlin 2.2.20 通过在 kotlin-maven-plugin
中添加对 Kotlin 守护进程 的支持,将 Kotlin 2.2.0 中引入的构建工具 API 更进一步。使用 Kotlin 守护进程时,Kotlin 编译器在单独的隔离进程中运行,这可以防止其他 Maven 插件覆盖系统属性。您可以在此 YouTrack 问题 中看到一个示例。
从 Kotlin 2.2.20 开始,默认使用 Kotlin 守护进程。如果您想恢复到以前的行为,请通过在您的 pom.xml
文件中将以下属性设置为 false
来选择退出:
markup
<properties>
<kotlin.compiler.daemon>false</kotlin.compiler.daemon>
</properties>
Kotlin 2.2.20 还引入了一个新的 jvmArgs
属性,您可以使用它来自定义 Kotlin 守护进程的默认 JVM 参数。例如,要覆盖 -Xmx
和 -Xms
选项,请将以下内容添加到您的 pom.xml
文件中:
markup
<properties>
<kotlin.compiler.daemon.jvmArgs>Xmx1500m,Xms500m</kotlin.compiler.daemon.jvmArgs>
</properties>
Kotlin 编译器选项的新通用模式
Kotlin 2.2.20 引入了一个通用模式,用于在 org.jetbrains.kotlin:kotlin-compiler-arguments-description
下发布的所有编译器选项。此工件包括所有编译器选项的代码表示和 JSON 等效项(适用于非 JVM 使用者)、它们的描述以及元数据,例如每个选项引入或稳定的版本。您可以使用此模式生成选项的自定义视图或根据需要进行分析。
Kotlin 标准库
此版本在标准库中引入了新的实验性功能:用于在 Kotlin/JS 中识别接口类型的反射支持、通用原子类型的更新函数以及用于调整数组大小的 copyOf()
重载。
支持通过 Kotlin/JS 中的反射识别接口类型
Kotlin 2.2.20 将 Experimental KClass.isInterface
属性添加到 Kotlin/JS 标准库中。
使用此属性,您现在可以检查类引用是否表示 Kotlin 接口。这使 Kotlin/JS 更接近与 Kotlin/JVM 的对等,在 Kotlin/JVM 中,您可以使用 KClass.java.isInterface
来检查类是否表示接口。
要选择加入,请使用 @OptIn(ExperimentalStdlibApi::class)
注解:
kotlin
@OptIn(ExperimentalStdlibApi::class)
fun inspect(klass: KClass<*>) {
// 对接口打印 true
println(klass.isInterface)
}
我们希望您能在我们的问题跟踪器 YouTrack 中提供反馈。
通用原子类型的新更新函数
Kotlin 2.2.20 引入了新的实验性函数,用于更新通用原子类型及其数组对应项的元素。每个函数都使用这些更新函数之一原子地计算一个新值并替换当前值,返回值取决于您使用的函数:
update()
和updateAt()
设置一个新值而不返回结果。fetchAndUpdate()
和fetchAndUpdateAt()
设置一个新值并返回更改前的前一个值。updateAndFetch()
和updateAndFetchAt()
设置一个新值并返回更改后的更新值。
您可以使用这些函数实现不受支持的原子转换,例如乘法或按位运算。在此更改之前,递增一个通用原子类型并读取前一个值需要一个带有 compareAndSet()
函数的循环。
与所有通用原子类型的 API 一样,这些函数是 Experimental。要选择加入,请使用 @OptIn(ExperimentalAtomicApi::class)
注解。
这是一个执行不同类型更新并返回前一个值或更新值的代码示例:
kotlin
import kotlin.concurrent.atomics.*
import kotlin.random.Random
@OptIn(ExperimentalAtomicApi::class)
fun main() {
val counter = AtomicLong(Random.nextLong())
val minSetBitsThreshold = 20
// 设置一个新值而不使用结果
counter.update { if (it < 0xDECAF) 0xCACA0 else 0xC0FFEE }
// 检索当前值,然后更新它
val previousValue = counter.fetchAndUpdate { 0x1CEDL.shl(Long.SIZE_BITS - it.countLeadingZeroBits()) or it }
// 更新值,然后检索结果
val current = counter.updateAndFetch {
if (it.countOneBits() < minSetBitsThreshold) it.shl(20) or 0x15BADL else it
}
val hexFormat = HexFormat {
upperCase = true
number {
removeLeadingZeros = true
}
}
println("Previous value: ${previousValue.toHexString(hexFormat)}")
println("Current value: ${current.toHexString(hexFormat)}")
println("Expected status flag set: ${current and 0xBAD != 0xBADL}")
}
目标:JVM 在 v.2.2.20 上运行
我们希望您能在我们的问题跟踪器 YouTrack 中提供反馈。
支持数组的 copyOf()
重载
Kotlin 2.2.20 为 copyOf()
函数引入了一个实验性重载。它适用于泛型类型 Array<T>
的数组和所有基元数组类型。
您可以使用此函数使数组变大,并使用初始化 lambda 的值填充新元素。这可以帮助您减少自定义样板代码,并修复了调整泛型 Array<T>
大小会产生可空结果 (Array<T?>
) 的常见痛点。
这是一个例子:
kotlin
@OptIn(ExperimentalStdlibApi::class)
fun main() {
val row1: Array<String> = arrayOf("one", "two")
// 调整数组大小并使用 lambda 填充新元素
val row2: Array<String> = row1.copyOf(4) { "default" }
println(row2.contentToString())
// [one, two, default, default]
}
此 API 是 Experimental。要选择加入,请使用 @OptIn(ExperimentalStdlibApi::class)
注解。
我们希望您能在我们的 问题跟踪器 中提供反馈。
Compose 编译器
在此版本中,Compose 编译器通过添加新警告和改进构建指标的输出来提高生活质量,使其更易于阅读。
默认参数的语言版本限制
从此版本开始,如果为编译指定的语言版本低于支持抽象或开放可组合函数中默认参数所需的版本,Compose 编译器会报告错误。
从 Kotlin 2.1.0 开始,Compose 编译器支持抽象函数中的默认参数,从 Kotlin 2.2.0 开始支持开放函数。在使用较新版本的 Compose 编译器同时针对较旧的 Kotlin 语言版本时,库开发人员应注意,抽象或开放函数中的默认参数可能仍会出现在公共 API 中,即使语言版本不支持它们。
K2 编译器的可组合目标警告
此版本在 K2 编译器中添加了有关 @ComposableTarget
不匹配的警告。
例如:
kotlin
@Composable fun App() {
Box { // <-- `Box` 是 `@UiComposable`
Path(...) // <-- `Path` 是 `@VectorComposable`
^^^^^^^^^
warning: Calling a Vector composable function where a UI composable was expected
}
}
构建指标中的完全限定名称
构建指标中报告的类和函数名称现在是完全限定的,这使得区分不同包中同名声明变得更加容易。
此外,构建指标不再包含来自默认参数的复杂表达式的转储,使其更易于阅读。
重大变更和弃用
本节重点介绍值得注意的重要重大变更和弃用:
- kapt 编译器插件现在默认使用 K2 编译器。因此,控制插件是否使用 K2 编译器的
kapt.use.k2
属性已被弃用。如果您将此属性设置为false
以选择不使用 K2 编译器,Gradle 会显示警告。
文档更新
Kotlin 文档发生了一些显着变化:
- Kotlin 路线图 -- 查看 Kotlin 在语言和生态系统演变方面的优先事项更新列表。
- 属性 -- 了解在 Kotlin 中使用属性的多种方式。
- 条件和循环 -- 了解 Kotlin 中的条件和循环如何工作。
- Kotlin/JavaScript -- 探索 Kotlin/JS 的用例。
- 针对 Web -- 了解 Gradle 为 Web 开发提供的不同目标。
- Kotlin 守护进程 -- 了解 Kotlin 守护进程及其如何与构建系统和 Kotlin 编译器一起工作。
- 协程概述页面 -- 了解协程概念并开始您的学习之旅。
- Kotlin/Native 二进制选项 -- 了解 Kotlin/Native 的二进制选项以及如何配置它们。
- 调试 Kotlin/Native -- 探索使用 Kotlin/Native 进行调试的不同方式。
- 自定义 LLVM 后端的提示 -- 了解 Kotlin/Native 如何使用 LLVM 并调整优化过程。
- 开始使用 Exposed 的 DAO API -- 了解如何使用 Exposed 的数据访问对象 (DAO) API 在关系数据库中存储和检索数据。
- Exposed 文档中有关 R2DBC 的新页面:
- HTMX 集成 -- 了解 Ktor 如何为 HTMX 提供实验性的一流支持。
如何更新到 Kotlin 2.2.20
Kotlin 插件作为 IntelliJ IDEA 和 Android Studio 中的捆绑插件分发。
要更新到新的 Kotlin 版本,请在您的构建脚本中 将 Kotlin 版本更改 为 2.2.20。