Котлин 1.3.11 сломал нуль-безопасность? - PullRequest
0 голосов
/ 06 января 2019
fun handle() : String {
    null?.let { return "Ololo"}
}

val result = handle()
result.trim() // kotlin.TypeCastException: null cannot be cast to non-null type kotlin.CharSequence

Есть идеи, почему нулевая безопасная функция Котлина возвращает ноль?

Ответы [ 3 ]

0 голосов
/ 06 января 2019

Это должна быть ошибка, потому что:

  • отсутствует оператор возврата (или лучше: выражение), поскольку лямбда, переданная в let, не будет вызвана
  • функция с String в качестве типа возврата никогда не должна возвращать null.

Интересно, что в Kotlin 1.2.x это даже не компилируется:

fun handle() : String {
    null?.let { return "Ololo"}
} 

Ошибка: (6, 0) выражение 'return' требуется для функции с телом блока ('{...}')

В Kotlin 1.3.11 это так.

В любом случае:

let вызываться не будет, поскольку оператор безопасного вызова ? оценивается как null (в данном случае).

0 голосов
/ 07 января 2019

Это ошибка, вызванная введением контрактов для стандартных функций let, run, apply, also в Kotlin 1.3.

Исправление предназначено для версии 1.3.20. Подробнее см. KT-28061 .

0 голосов
/ 06 января 2019

Похоже, компилятор Kotlin добавляет в null возврат, если let не выполняется. Вероятно, это ошибка, так как она не должна компилироваться, и не в предыдущих версиях Kotlin.

Если мы просто скомпилируем ваш пример, мы получим это:

@NotNull
public final String handle() {
    return null;
}

Я думаю, что это просто оптимизация компилятора, поскольку null?.let() никогда не выполнится.

Использование фактической переменной дает:

@NotNull
public final String handle() {
    return someNullableVariable != null ? "Ololo" : null;
}

Другими словами, let() не выполняется, если его ссылка null. Однако, поскольку эта функция должна что-то возвращать, компилятор просто сообщает ей, чтобы она возвращала null, поскольку больше ничего она не могла бы вернуть.

Поскольку функция помечена @NotNull, Kotlin будет выполнять нулевую проверку всего, что ссылается на функцию:

fun someOtherMethod() {
    handle().trim()
}

становится

public final void someOtherMethod() {
    String handle = handle();

    if (handle != null) {
        StringsKt__StringsKt.trim(handle).toString();
        return;
    }

    throw new Exception("null cannot be cast to non-null type kotlin.CharSequence");
}

Есть два способа справиться с этим. Вы можете изменить тип возврата на handle() на String?:

fun handle(): String? {
    someNullableVariable?.let { return "Ololo" }
}

Или вы можете вернуть что-то еще, если переменная равна нулю:

fun handle(): String {
    someNullableVariable?.let { return "Ololo" }
    return "someNullableVariable was null"
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...