智能转换与 KOTLIN 中的显式转换有何不同

Kav*_*eri 6 optimization performance android casting kotlin

最近,我读到了有关运算符执行的智能强制转换的信息is,以及有关用于显式强制转换的as或更好的运算符的信息。as?

kotlin 文档将其用法差异分类如下:-

请注意,当编译器无法保证变量在检查和使用之间不会更改时,智能转换不起作用。更具体地说,智能转换根据以下规则适用:

  • val 局部变量 - 始终除了局部委托属性;

  • val 属性 - 如果属性是私有的或内部的,或者检查是在声明该属性的同一模块中执行的。智能转换不适用于开放属性或具有自定义 getter 的属性;

  • var 局部变量 -如果该变量在检查和使用之间未修改,则未在修改它的 lambda 中捕获,并且不是本地委托属性;

  • var 属性 - 从不(因为该变量可以随时被其他代码修改)。

请注意,当编译器无法保证变量在检查和使用之间不会更改时,智能转换不起作用。

上面写的有点令人困惑,因为var变量可以在初始化后更改,而且我找不到可以清楚说明该语句的实际含义的示例。

无论如何,任何人都可以更容易地更好地理解这一见解吗?

运营商是否is提供了一些优于as运营商的优化优势(如果有的话)?

Sha*_*arp 7

智能强制转换的想法是帮助您避免使用asas?显式强制转换已经检查过的内容。至于上面的要点,这里有一些例子。

  • val 局部变量 - 由于 val 是最终的(无法更改),因此在进行检查后,该变量可以进行智能转换,因为它不能再次更改。
val a: Int? = 2
if (a is Int) {
    // 'a' is smart cast to Int
    val b = a * 2 // b is also Int
}
Run Code Online (Sandbox Code Playgroud)
  • val 属性 - 如果直接访问(通过默认的 getter),则可以进行智能转换。如果通过自定义 getter,这并不是因为我们无法知道它被修改了。
class Test {
    val a: Int? = 2;
}

class TestGetter {
    val a: Int? = 2
        get() = field * 2
}

// Usage
val test = Test()
val testGetter = TestGetter()

if (test.a is Int) {
    // 'test.a' is smart cast to Int
    val b = test.a * 2
}

if (testGetter.a is Int) {
    // smart cast is impossible, 'testGetter.a' is still Int?
    val b = testGetter.a * 2 // can't happen because we don't know whether 'a' was changed by the custom getter or not (the getter could give unstable values)
}
Run Code Online (Sandbox Code Playgroud)
  • var 局部变量 - 如果该变量在检查和使用之间未修改,则不会在修改它的 lambda 中捕获,并且不是本地委托属性;
var a: Int? = 2
if (a is Int) {
    // 'a' was not changed, so it can be smart cast to Int
    val b = a * 2 // b is also Int
}

var c = 4
if (c is Int) {
    c = null
    // 'c' was changed between the check and the usage, we cannot smart cast it anymore
    val b = c * 2 // won't work
}
Run Code Online (Sandbox Code Playgroud)

var 属性 - var 总是可以被代码中的其他内容修改,因此智能转换将不起作用。

class Example {
    var a: Int? = 2

    fun test1() {
        if (a is Int) {
            // smart cast is impossible because we don't know whether 'a' was changed by some other code/function
            val b = a * 2 // won't work
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

就使用as而言,如果您看一下最后一个示例:

class Example {
    var a: Int? = 2

    fun test1() {
        if (a is Int) {
            // smart cast is impossible because we don't know whether 'a' was changed by some other code/function
            val b = a as Int * 2 // this WILL work because we forcefully cast it to Int, but if a is null there will be an exception in runtime
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

as?当您不确定 var 是否可以转换为某些内容时,您也可以使用。如果没有,它只会给你一个空值。例如:

val a: Double = 2.0
val b = a as? String // 'b' will be 'String?', in this case initialized to 'null' since 'a' cannot be cast to it

val c: Int? = 2
val d = c as? Int // 'd' will be '2' but still 'Int?' since 'as?' always makes the variable nullable
Run Code Online (Sandbox Code Playgroud)

希望这些例子有帮助,如果我需要进一步澄清一些事情,请告诉我。