Kotlin - `if` 和 `when` 表达式的类型
Kotlin - Type of `if` and `when` Expressions
我知道 Kotlin 是一种静态类型语言,所有类型都是在编译时定义的。
这是 when
表达式,returns 不同类型:
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 甚至警告您 Conditional branch result of type X is implicitly cast to Any
,至少 Android Studio 和 Kotlin Playground.
一样
在编译时,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
类型的对象。
感谢 的快速解释:
There's a difference between the declared type of a variable and the actual type of the object it references. It's no different than doing val x: Any = "Hello, Wold!"
;
该变量的类型是 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.
}
}
我知道 Kotlin 是一种静态类型语言,所有类型都是在编译时定义的。
这是 when
表达式,returns 不同类型:
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 甚至警告您 Conditional branch result of type X is implicitly cast to Any
,至少 Android Studio 和 Kotlin Playground.
在编译时,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
类型的对象。
感谢
There's a difference between the declared type of a variable and the actual type of the object it references. It's no different than doing
val x: Any = "Hello, Wold!"
;
该变量的类型是 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.
}
}