一、概述
The Kotlin 2.0.0 release is out and the new Kotlin K2 compiler is Stable! Additionally, here are some other highlights:
Kotlin 2.0.0发布了,新的Kotlin K2编译器已经稳定了。此外,以下是其他一些亮点:
- New Compose compiler Gradle plugin
- Generation of lambda functions using invokedynamic
- The kotlinx-metadata-jvm library is now Stable
- Monitoring GC performance in Kotlin/Native with signposts on Apple platforms
- Resolving conflicts in Kotlin/Native with Objective-C methods
- Support for named export in Kotlin/Wasm
- Support for unsigned primitive types in functions with @JsExport in Kotlin/Wasm
- Optimize production builds by default using Binaryen
- New Gradle DSL for compiler options in multiplatform projects
- Stable replacement of the enum class values generic function
- Stable AutoCloseable interface
二、局部变量和进一步的作用域
以前,如果一个变量在if条件中被计算为非空,则该变量将被智能强制转换。关于这个变量的信息将在if块的范围内进一步共享。
但是,如果在if条件之外声明变量,则在if条件中无法获得有关该变量的信息,因此无法对其进行智能强制转换。这种行为在when表达式和while循环中也可以看到。
从Kotlin 2.0.0开始,如果在if、when或while条件中使用一个变量之前声明它,那么编译器收集的关于该变量的任何信息都可以在相应的块中进行智能转换。
当您想要将布尔条件提取到变量中时,这可能很有用。然后,您可以为变量指定一个有意义的名称,这将提高代码的可读性,并使以后在代码中重用该变量成为可能。例如:
三、使用逻辑或运算符进行类型检查
在Kotlin 2.0.0中,如果您将对象的类型检查与or操作符(||)结合起来,则会对其最接近的公共超类型进行智能强制转换。在此更改之前,总是对Any类型进行智能强制转换。
在这种情况下,您仍然必须手动检查对象类型,然后才能访问其任何属性或调用其函数。例如:
class Cat {
//咕噜声
fun purr() {
print("cat Purr purr")
}
}
fun petAnimal(animal: Any) {
val isCat = animal is Cat
if (isCat) {
//在Kotlin 2.0.0中,编译器可以访问关于isCat的信息,
// 所以它知道动物被智能铸造为Cat类型。因此,可以调用purr()函数。
//在Kotlin 1.9.20中,编译器不知道
//调用purr()函数触发错误。
// animal.purr()
// 2.0之前的版本,
// (animal as Cat).purr()
}
}
fun main() {
val ketty = Cat()
petAnimal(ketty)
}
四、使用逻辑或运算符进行类型检查
在Kotlin 2.0.0中,如果您将对象的类型检查与or操作符(||)结合起来,则会对其最接近的公共超类型进行智能强制转换。在此更改之前,总是对Any类型进行智能强制转换。
在这种情况下,您仍然必须手动检查对象类型,然后才能访问其任何属性或调用其函数。例如:
interface Status {
fun signal() {}
}
interface Ok : Status
interface Postponed : Status
interface Declined : Status
fun signalCheck(signalStatus: Any) {
if (signalStatus is Postponed || signalStatus is Declined) {
// signalStatus is smart-cast to a common supertype Status; signalStatus被智能转换为一个普通的超类型Status
// signalStatus.signal()
// Prior to Kotlin 2.0.0, signalStatus is smart cast; 在Kotlin 2.0.0之前,signalStatus是智能强制转换
// to type Any, so calling the signal() function triggered an ; 输入Any,所以调用signal()函数会触发一个
// Unresolved reference error. The signal() function can only; 未解析的引用错误。signal()函数只能
// be called successfully after another type check: ; 在另一次类型检查后被成功调用:
// check(signalStatus is Status)
// signalStatus.signal()
}
}
五、内联函数
在Kotlin 2.0.0中,K2编译器以不同的方式处理内联函数,允许它结合其他编译器分析来确定智能强制转换是否安全。
具体来说,内联函数现在被视为具有隐式的callsInPlace契约。这意味着任何传递给内联函数的lambda函数都会被就地调用。由于lambda函数是就地调用的,编译器知道lambda函数不会泄漏对其函数体中包含的任何变量的引用。
编译器使用这些知识和其他编译器分析来决定智能转换捕获的任何变量是否安全。例如:
interface Processor {
fun process()
}
inline fun inlineAction(f: () -> Unit) = f()
fun nextProcessor(): Processor? = null
fun runProcessor(): Processor? {
var processor: Processor? = null
inlineAction {
// In Kotlin 2.0.0, the compiler knows that processor
// is a local variable, and inlineAction() is an inline function, so
// references to processor can't be leaked. Therefore, it's safe
// to smart-cast processor.
// If processor isn't null, processor is smart-cast
if (processor != null) {
// The compiler knows that processor isn't null, so no safe call
// is needed
processor.process()
// In Kotlin 1.9.20, you have to perform a safe call:
// processor?.process()
}
processor = nextProcessor()
}
return processor
}
六、函数类型的属性
在Kotlin的早期版本中,有一个bug意味着带有函数类型的类属性不能智能强制转换。我们在Kotlin 2.0.0和K2编译器中修复了这个行为。例如:
class Holder(val provider: (() -> Unit)?) {
fun process() {
// In Kotlin 2.0.0, if provider isn't null, then
// provider is smart-cast
if (provider != null) {
// The compiler knows that provider isn't null
provider()
// In 1.9.20, the compiler doesn't know that provider isn't
// null, so it triggers an error:
// Reference has a nullable type '(() -> Unit)?', use explicit '?.invoke()' to make a function-like call instead
}
}
}
如果重载调用操作符,也适用此更改。例如:
interface Provider {
operator fun invoke()
}
interface Processor : () -> String
class Holder(val provider: Provider?, val processor: Processor?) {
fun process() {
if (provider != null) {
provider()
// In 1.9.20, the compiler triggers an error:
// Reference has a nullable type 'Provider?' use explicit '?.invoke()' to make a function-like call instead
}
}
}
七、异常处理
在Kotlin 2.0.0中,我们对异常处理进行了改进,以便将智能强制转换信息传递给catch和finally块。此更改使代码更安全,因为编译器会跟踪对象是否具有可空类型。例如:
fun testString() {
var stringInput: String? = null
// stringInput is smart-cast to String type
stringInput = ""
try {
// The compiler knows that stringInput isn't null
println(stringInput.length)
// 0
// The compiler rejects previous smart cast information for
// stringInput. Now stringInput has the String? type.
stringInput = null
// Trigger an exception
if (2 > 1) throw Exception()
stringInput = ""
} catch (exception: Exception) {
// In Kotlin 2.0.0, the compiler knows stringInput
// can be null, so stringInput stays nullable.
println(stringInput?.length)
// null
println("捕获到的异常信息:$exception")
// In Kotlin 1.9.20, the compiler says that a safe call isn't
// needed, but this is incorrect.
}finally {
println("执行了 finally 逻辑")
}
}
运行结果
八、kt_200.kt文件代码
package com.example.test.ktversion
// https://kotlinlang.org/docs/whatsnew20.html
class Cat {
//咕噜声
fun purr() {
print("cat Purr purr")
}
}
fun petAnimal(animal: Any) {
val isCat = animal is Cat
if (isCat) {
//在Kotlin 2.0.0中,编译器可以访问关于isCat的信息,
// 所以它知道动物被智能铸造为Cat类型。因此,可以调用purr()函数。
//在Kotlin 1.9.20中,编译器不知道
//调用purr()函数触发错误。
// animal.purr()
// 2.0之前的版本,
// (animal as Cat).purr()
}
}
// Type checks with logical or operator 将对象的类型检查与or操作符(||)结合起来
interface Status {
fun signal() {}
}
interface Ok : Status
interface Postponed : Status
interface Declined : Status
fun signalCheck(signalStatus: Any) {
if (signalStatus is Postponed || signalStatus is Declined) {
// signalStatus is smart-cast to a common supertype Status; signalStatus被智能转换为一个普通的超类型Status
// signalStatus.signal()
// Prior to Kotlin 2.0.0, signalStatus is smart cast; 在Kotlin 2.0.0之前,signalStatus是智能强制转换
// to type Any, so calling the signal() function triggered an ; 输入Any,所以调用signal()函数会触发一个
// Unresolved reference error. The signal() function can only; 未解析的引用错误。signal()函数只能
// be called successfully after another type check: ; 在另一次类型检查后被成功调用:
// check(signalStatus is Status)
// signalStatus.signal()
}
}
// Inline functions
interface Processor {
fun process()
}
inline fun inlineAction(f: () -> Unit) = f()
fun nextProcessor(): Processor? = null
fun runProcessor(): Processor? {
var processor: Processor? = null
inlineAction {
// In Kotlin 2.0.0, the compiler knows that processor ; 在Kotlin 2.0.0中,编译器知道这个处理器
// is a local variable, and inlineAction() is an inline function, so ; 是一个局部变量,而inlineAction()是一个内联函数,所以
// references to processor can't be leaked. Therefore, it's safe ; 对处理器的引用不能泄露。因此,它是安全的
// to smart-cast processor. ; 到智能转换处理器。
// If processor isn't null, processor is smart-cast; 如果processor不为空,则processor是smart-cast
if (processor != null) {
// The compiler knows that processor isn't null, so no safe call; 编译器知道处理器不是null,所以没有安全调用
// is needed ; 需要
// processor.process()
// In Kotlin 1.9.20, you have to perform a safe call:
// processor?.process()
}
processor = nextProcessor()
}
return processor
}
// Properties with function types 函数类型的属性
class Holder(val provider: (() -> Unit)?) {
fun process() {
// In Kotlin 2.0.0, if provider isn't null, then
// provider is smart-cast
if (provider != null) {
// The compiler knows that provider isn't null
// provider()
// In 1.9.20, the compiler doesn't know that provider isn't
// null, so it triggers an error:
// Reference has a nullable type '(() -> Unit)?', use explicit '?.invoke()' to make a function-like call instead
}
}
}
//This change also applies if you overload your invoke operator. For example:
interface Provider {
operator fun invoke()
}
interface Processor2 : () -> String
class Holder2(val provider: Provider?, val processor: Processor2?) {
fun process() {
if (provider != null) {
// provider()
// In 1.9.20, the compiler triggers an error:
// Reference has a nullable type 'Provider?' use explicit '?.invoke()' to make a function-like call instead
}
}
}
// 异常处理
fun testString() {
var stringInput: String? = null
// stringInput is smart-cast to String type
stringInput = ""
try {
// The compiler knows that stringInput isn't null
println(stringInput.length)
// 0
// The compiler rejects previous smart cast information for
// stringInput. Now stringInput has the String? type.
stringInput = null
// Trigger an exception
if (2 > 1) throw Exception()
stringInput = ""
} catch (exception: Exception) {
// In Kotlin 2.0.0, the compiler knows stringInput
// can be null, so stringInput stays nullable.
println(stringInput?.length)
// null
println("捕获到的异常信息:$exception")
// In Kotlin 1.9.20, the compiler says that a safe call isn't
// needed, but this is incorrect.
}finally {
println("执行了 finally 逻辑")
}
}
fun main() {
val ketty = Cat()
petAnimal(ketty)
testString()
}