Kotlin:2.0.0 的新特性

一、概述

kotlin 2.0.0版本英文官方文档

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编译器已经稳定了。此外,以下是其他一些亮点:

二、局部变量和进一步的作用域

以前,如果一个变量在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()
}
相关推荐
云空6 分钟前
《解锁 Python 数据挖掘的奥秘》
开发语言·python·数据挖掘
青莳吖17 分钟前
Java通过Map实现与SQL中的group by相同的逻辑
java·开发语言·sql
Buleall24 分钟前
期末考学C
java·开发语言
重生之绝世牛码26 分钟前
Java设计模式 —— 【结构型模式】外观模式详解
java·大数据·开发语言·设计模式·设计原则·外观模式
戏谑30 分钟前
Android 常用布局
android·view
小蜗牛慢慢爬行32 分钟前
有关异步场景的 10 大 Spring Boot 面试问题
java·开发语言·网络·spring boot·后端·spring·面试
Algorithm157642 分钟前
云原生相关的 Go 语言工程师技术路线(含博客网址导航)
开发语言·云原生·golang
shinelord明1 小时前
【再谈设计模式】享元模式~对象共享的优化妙手
开发语言·数据结构·算法·设计模式·软件工程
Monly211 小时前
Java(若依):修改Tomcat的版本
java·开发语言·tomcat
boligongzhu1 小时前
DALSA工业相机SDK二次开发(图像采集及保存)C#版
开发语言·c#·dalsa