Логично, что Котлин не замыкает накоротко? - PullRequest
0 голосов
/ 03 февраля 2019

Я следовал по документации Kotlin на http://kotlinlang.org/docs/reference/null-safety.html#checking-for-null-in-conditions и пытался адаптировать этот пример,

val b = "Kotlin"
if (b != null && b.length > 0) {
    print("String of length ${b.length}")
} else {
    print("Empty string")
}

к случаю, когда b = null.В проекте IntelliJ Idea Kotlin у меня есть app.kt с функцией main(), определенной как:

fun main() {
    val b = null
    if (b != null && b.length > 0) {
        print("String of length ${b.length}")
    } else {
        print("Empty string")
    }
}

Однако, когда я запускаю это, я получаю две ошибки компиляции:

Information:Kotlin: kotlinc-jvm 1.3.20 (JRE 11+28)
Information:2019-02-02 15:07 - Compilation completed with 2 errors and 0 warnings in 1 s 921 ms
/Users/kurtpeek/IdeaProjects/HelloWorld/src/app.kt
Error:(3, 24) Kotlin: Unresolved reference: length
Error:(4, 37) Kotlin: Unresolved reference: length

Я понимаю, что компилятор оценивает b.length, хотя первое условие, b != null, это false.Это удивляет меня, потому что я подумал, что первой проверкой было «замкнуть» булево выражение при необходимости и сделать вызов b.length «safe».

Например, в Python вы можете сделать это:

In [1]: "foo" == "bar" and what.the.heck
Out[1]: False

, который работает, даже если what не определено, потому что and «останавливается», поскольку "foo" не равно "bar".

Действительно ли этокак работает котлин?Кажется, что отсутствие функции «короткого замыкания» в Python было бы ограничением.

Ответы [ 2 ]

0 голосов
/ 03 февраля 2019

Из вашего связанного текста: «Обратите внимание, что это работает только тогда, когда b является неизменным (т. Е. Локальной переменной, которая не изменяется между проверкой и использованием, или членом-членом, который имеет вспомогательное поле и не может быть переопределен)».

val b=null является неизменным, но поскольку тип нулевого значения не может быть выведен или сохранен, его нельзя использовать в качестве источника в допустимом ярлыке.

Если вы изменили код, чтобы дать емуобнуляемый тип, и установите это значение в ноль, это будет работать.

0 голосов
/ 03 февраля 2019

Оператор Котлина && будет иметь короткое замыкание (точно так же как Java), но только во время выполнения.То, что вы испытываете, это ошибка компиляции .Особенно важно помнить при сравнении Kotlin (или Java) с Python то, что Kotlin и Java статически типизированы и имеют фазу компиляции.Таким образом, вы получите ошибку компиляции, если типы не совпадают.

Давайте пройдемся по одному за раз ...

val b = "Kotlin"
if (b != null && b.length > 0) {
    ...
}

В этом случае Котлин правильно сделает вывод, что b - это тип String, потому что вы четко его установилиСтруне ("Котлин").Здесь следует отметить, что тип String не может содержать ноль.Зная это, часть b != null вашего утверждения if не нужна.Тем не менее, после оценки этого (до истины, всегда) он будет оценивать b.length, потому что b является String и, следовательно, имеет свойство length.Этот пример должен нормально скомпилироваться (я его не тестировал).

И далее ...

val b = null
if (b != null && b.length > 0) {
    ...
}

Этот код не скомпилируется, давайте рассмотрим, почему...

Этот код выглядит действительно похожим, но имеет одно огромное отличие.В этом случае, поскольку вы просто установили b на null, Котлин сделает вывод, что b является Nothing?.Он не имеет информации о том, какой тип вы хотите, чтобы b был, и вы установили для него значение NULL (и поскольку это val, оно будет всегда быть null).Поскольку b равно null, это делает b обнуляемым.

Итак, учитывая, что когда мы компилируем b != null, это всегда не удастся, потому что b можетникогда не будет чем-то, что не null.Но ждать!Мы сейчас компилируем ... и когда мы сталкиваемся с b.length, Kotlin выдаст ошибку компиляции , потому что Nothing? не имеет свойства length!

По сути, установив b в null и не предоставив подсказку типа, Kotlin выбирает единственный путь, которым он может вывести тип - Nothing?.

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