Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin-if`和when`表达式的类型_Kotlin_Jvm_Static Typing - Fatal编程技术网

Kotlin-if`和when`表达式的类型

Kotlin-if`和when`表达式的类型,kotlin,jvm,static-typing,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上的Kotl

我知道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
的类型?

实际上,在这种情况下,when表达式的类型解析为
Any
,因此
y
变量可以有任何值。IDE甚至警告您,类型X的
条件分支结果被隐式转换为任何
,至少Android Studio是这样做的。

在编译时,
y
的推断类型是
Any
,这是Kotlin中所有类型的超类型。在运行时,
y
可以[字面上]引用任何类型的对象。IDE生成警告
“Int/String/Float类型的条件分支结果隐式转换为任何”

在这个例子中

x
=1时,它引用类型为
java.lang.Integer
的对象

x
=2时,它引用类型为
java.lang.String
的对象

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


感谢您的快速解释:

变量的声明类型与其引用的对象的实际类型之间存在差异。这与执行
val x: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.
    }
}

最有可能的是
y
被键入为
Any
,这是所有类型的常见超类型。换句话说,显式键入时它看起来像
val y:Any=when(x){…}
@Slaw,这是我猜测的,但想知道
Any
如何在
println中转换为
Integer
String
等(y::class.java)
语句。它不是。变量的声明类型和它引用的对象的实际类型之间存在差异。这与执行
val x:Any=“你好,Wold!”没有什么区别;
。通常,它解析为所有相关类型中最接近的公共超类型。例如,如果分支返回一个
列表和一个
集合
,则生成的类型将是
集合
(类似地,其类型参数将是这些类型中最接近的公共超类型)。(奇怪的是,这似乎不适用于数字类型;您可能希望它为
Int
Float
推断
Number
,但它推断
Any
。不确定为什么…)这是一个很好的解释!因此
when
表达式返回最小可能的超类,这很有意义。