Kotlin-if`和when`表达式的类型
我知道Kotlin是一种静态类型语言,所有类型都是在编译时定义的 下面是一个返回不同类型的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
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
表达式返回最小可能的超类,这很有意义。