Kotlin-“ if”和“ when”表达式的类型

时间:2019-10-21 04:29:11

标签: kotlin jvm static-typing

我了解Kotlin是一种静态类型的语言,并且所有类型都是在编译时定义的。

这里是一个when表达式,它返回不同的类型:

fun main(){

    val x = readLine()?.toInt() ?: 0

    val y = when(x){
        1 -> 42
        2 -> "Hello"
        else -> 3.14F
    }

    println(y::class.java)
}

在运行时(JVM 1.8上的Kotlin 1.3.41),这是输出:

x = 1时,它将打印class java.lang.Integer

x = 2时,它将打印class java.lang.String

否则,它将打印class java.lang.Float

编译器何时确定y的类型?或者,在编译期间,编译器如何推断y的类型?

3 个答案:

答案 0 :(得分:2)

实际上,在这种情况下,when表达式的类型解析为INSTR,因此Any变量可以具有任何值。 IDE甚至会警告您y,至少是Android Studio,还有Kotlin Playground

答案 1 :(得分:2)

该变量的类型为Any(作为所有这些类型中最小的超类),但基本值未受影响。

是什么意思?您只能安全地访问所有所有类型共有的属性(因此,仅Any类型可用的属性。::class.java属性适用于所有类型。

请参阅此示例-我使用其他一些类型来很好地了解其含义。

abstract class FooGoo {
    fun foogoo(): String = "foo goo"
}

class Foo: FooGoo() {
    fun foo(): String = "foo foo"
}

class Goo: FooGoo() {
    fun goo(): String = "goo goo"
}

class Moo {
    fun moo(): String = "moo moo"
}

fun main(x: Int) {
    val n = when (x) {
        0 -> Foo()
        1 -> Goo()
        else -> throw IllegalStateException()
    } // n is implicitly cast to FooGoo, as it's the closes superclass of both, Foo and Goo

    // n now has only methods available for FooGoo, so, only `foogoo` can be called (and all methods for any)

    val m = when (x) {
        0 -> Foo()
        1 -> Goo()
        else -> Moo()
    } // m is implicitly cast to Any, as there is no common supertype except Any

    // m now has only methods available for Any() - but properties for that class are not changed
    // so, `m::class.java` will return real type of that method.

    println(m::class.java) // // Real type of m is not erased, we still can access it

    if (m is FooGoo) { 
        m.foogoo() // After explicit cast we are able to use methods for that type.
    }
}

答案 2 :(得分:0)

在编译期间,y的推断类型为Any,它是Kotlin中所有类型的超类型。在运行时,y可以[字面意义上]引用任何类型的对象。 IDE生成警告"Conditional branch result of type Int/String/Float is implicitly cast to Any"

在示例中,

x = 1时,它指向类型为java.lang.Integer的对象。

x = 2时,它指向类型为java.lang.String的对象。

否则,它引用类型为java.lang.Float的对象。


感谢Slaw的简要说明:

  

变量的声明类型与它引用的对象的实际类型之间是有区别的。和做val x: Any = "Hello, Wold!"没什么不同;