Котлин: Нулевая проверка, если блок - PullRequest
0 голосов
/ 16 апреля 2019

Я недавно начал изучать Котлин. Одна вещь, которую я не могу понять - блоки проверки нуля. Следующее утверждение считается небезопасным, и компилятор не позволит вам его скомпилировать.

    var testVar: String? = null;

    // if (testVar != null )
    {
        // Doing some work....
        println(testVar.length)
    }

Но когда вы раскомментируете строку if, все работает. Это кажется великолепным.

Но что, если // Doing some work.... вычислительно дорог, и другой поток изменяет значение testVar на null, пока этот поток находится в строке // Doing some work? В этом сценарии:

  • Выдает ли программа исключение NullPointerException?
  • ИЛИ:
  • Кэширует ли байт-код значение testVar и использует ли кэшированное значение внутри блока if?

1 Ответ

3 голосов
/ 16 апреля 2019

В вашем первоначальном примере ваш var является локальным для функции? Например:

fun doStuff() {
    var testVar: String? = null

    if (testVar != null) {
        println(testVar.length)
    }
}

В этом случае ни одна другая область не имеет ссылки на testVar, поэтому ничто другое не может ее изменить. Однако, если var является свойством класса, то есть

class MyClass {
    var testVar: String? = null

    fun doStuff() {
        if (testVar != null) {
            println(testVar.length)
        }
    }
}

Это не удастся скомпилировать, поскольку testVar мог быть установлен равным нулю другим потоком между проверкой и использованием.

Идем дальше, если вы пытаетесь быть хитрым:

fun doStuff() {
    var testVar: String? = null

    fun trickyFunction() {
        testVar = null
    }

    if (testVar != null) {
        trickyFunction()
        println(testVar.length)
    }
}

Компилятор потерпит неудачу, так как ваша переменная захвачена изменяющимся замыканием. Поэтому, в общем, если вы можете использовать переменную посредством умного приведения к ненулевому значению, вам не нужно беспокоиться о потенциальной возможности NPE.

Для второго сценария (свойства var) предпочтительно полагаться на .let для захвата неизменной ссылки на текущее значение, т. Е.

testVar?.let { capturedTestVar ->
    println(capturedTestVar.length)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...