Kotlin - Тип выражений `if` и` when` - PullRequest
2 голосов
/ 21 октября 2019

Я понимаю, что Kotlin - это статически типизированный язык, и все типы определены во время компиляции.

Вот выражение when, которое возвращает разные типы:

fun main(){

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

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

    println(y::class.java)
}

Во время выполнения (Kotlin 1.3.41 на JVM 1.8) это вывод:

Когда x = 1, он печатает class java.lang.Integer

Когда x = 2,он печатает class java.lang.String

В противном случае он печатает class java.lang.Float

Когда компилятор определяет тип y? Или как компилятор определяет тип y во время компиляции?

Ответы [ 3 ]

2 голосов
/ 21 октября 2019

Тип этой переменной для вас: 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 голосов
/ 21 октября 2019

На самом деле тип выражения when разрешается в Any в этом случае, поэтому переменная y может иметь любое значение. IDE даже предупреждает вас, что Conditional branch result of type X is implicitly cast to Any, по крайней мере, Android Studio, а также Kotlin Playground .

0 голосов
/ 21 октября 2019

Во время компиляции предполагаемый тип 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!";

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...