Не удалось определить тип Котлина

Этот код Котлин:

fun badKotlin(text: String?): Boolean {
    if (text == null) {
        return true
    }

    var temp = text
    if (false) {
        temp = Arrays.deepToString(arrayOf(text))
    } 

    return temp.isBlank() // <-- only safe (?.) or non null asserted (!!.) calls
}

не компилируется с сообщением: only safe (?.) or non null asserted (!!.) calls are allowed on a nullable receiver of type String?

Но если я добавлю else:

fun badKotlin(text: String?): Boolean {
    if (text == null) {
        return true
    }

    var temp = text
    if (false) {
        temp = Arrays.deepToString(arrayOf(text))
    } else {
        temp = Arrays.deepToString(arrayOf(text))
    }

    return temp.isBlank()
}

все скомпилировано. Итак, почему вывод типа не удался?

Если я изменю тип температуры на var temp: String = text это успешно составлено! Итак, более того, если мы изменим назначение temp следующим образом: temp = String.format("%s", text) это тоже скомпилировано.

ОБНОВИТЬ:

Успешно скопировано:

fun badKotlin(text: String?): Boolean {
    if (text == null) {
        return true
    }

    var temp = text
    if (false) {
        temp = String.format("%s", text)
    } 

    return temp.isBlank() // <-- only safe (?.) or non null asserted (!!.) calls
}

И это:

fun badKotlin(text: String?): Boolean {
    if (text == null) {
        return true
    }

    var temp: String = text
    if (false) {
        temp = Arrays.deepToString(arrayOf(text))
    } 

    return temp.isBlank() // <-- only safe (?.) or non null asserted (!!.) calls
}

2 ответа

Решение

Вы можете подумать, что после

if (text == null) {
    return true
}

тип text уточняется до String вместо String?,

Но похоже, что это не так; вместо этого компилятор вставляет умный бросок, когда видит text используется где String необходимо. в

var temp = text

В строке нет причин вставлять приведение, поэтому компилятор этого не делает, а тип temp является String?,

Если ты пишешь

var temp: String = text

приведение необходимо, и поэтому компилятор вставляет его.

Если ты пишешь

if (...) {
    temp = Arrays.deepToString(arrayOf(text))
} else {
    temp = Arrays.deepToString(arrayOf(text))
}

компилятор видит, что что бы ни случилось, temp было присвоено значение типа платформы String! который снова может быть умным приведением к String, Без else филиал, этого не происходит.

РЕДАКТИРОВАТЬ:

Любопытно, если вы просто удалите if и уходи

fun badKotlin(text: String?): Boolean {
    if (text == null) {
        return true
    }

    var temp = text

    return temp.isBlank()
}

он компилируется, и если бы мое объяснение было полным, я бы этого не ожидал. Таким образом, компилятор поддерживает информацию, необходимую для интеллектуального приведения, но, похоже, его не применяют, потому что

В частности, смарт-броски применяются в соответствии со следующими правилами:...

  • var локальные переменные - если переменная не изменена между проверкой и использованием, не записывается в лямбду, которая ее изменяет, и не является локальным делегированным свойством;

в if-else В этом случае назначения в двух филиалах вместе служат еще одной проверкой; в if -только одна ветка не

Назначая text в tempтип темп станет String?, тоже. Как это:

var temp: String? = text

Так как ваш if (false) никогда не будет выполнен, это не имеет никакого влияния на код. else добавляет блок, который всегда выполняется (так как это в основном означает if (true)) и назначает String в temp это не обнуляемо. Поскольку во втором примере temp не обнуляется, вам больше не нужно использовать операторы безопасного вызова...

Другие вопросы по тегам