Как передать тип nullable в функцию, которая принимает непустой тип?

Это возможно, если я делаю нулевую проверку перед прохождением? Например:

fun main(args: Array<String>) { var num: Int? = null // Stuff happens that might make num not null ... if (num != null) doSomething(num) } fun doSomething(number: Int) { ... } 

Я не понимаю, почему компилятор не разрешит мне пропускать значение, равное нулю, даже если я проверю, что он не первый. Может ли кто-нибудь объяснить?

ПРИМЕЧАНИЕ. Начиная с версии 1.0 компилятора, этот код работает как

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


http://kotlinlang.org/docs/reference/null-safety.html#checking-for-null-keyword–in-conditions говорит

Компилятор отслеживает информацию об [null] check … это работает только там, где b является неизменяемым (то есть локальный val или член val, который имеет поле поддержки и не является переопределяемым), поскольку в противном случае может случиться так, что b изменится на null после проверки.

Итак, что-то вроде этого должно работать:

 fun main(args: Array<String>) { var num: Int? = null // Stuff happens that might make num not null ... val numVal: Int? = num if (numVal != null) doSomething(numVal) } fun doSomething(number: Int) { ... } 

Конечно, было бы лучше переписать «материал» таким образом, чтобы вы могли сделать num в val в первую очередь.

В текущем Kotlin (1.0 beta или новее) у вас больше нет этой проблемы. Ваш код будет скомпилирован. Локальная переменная, которая является val или var может безопасно использовать Smart Cast, поскольку компилятор может определить, могло ли это значение быть изменено или нет (например, в другом потоке).

Вот выдержка из другого вопроса о переполнении стека, который охватывает больше аспектов недействительности и операторов Котлина для работы с ними.

Подробнее о null Checking и Smart Casts

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

 val possibleXyz: Xyz? = ... if (possibleXyz != null) { // allowed to reference members: possiblyXyz.foo() // or also assign as non-nullable type: val surelyXyz: Xyz = possibleXyz } 

Или, если вы делаете a, is проверка типа с нулевым значением:

 if (possibleXyz is Xyz) { // allowed to reference members: possiblyXyz.foo() } 

И то же самое для выражений «when», которые также безопасны:

 when (possibleXyz) { null -> doSomething() else -> possibleXyz.foo() } // or when (possibleXyz) { is Xyz -> possibleXyz.foo() is Alpha -> possibleXyz.dominate() is Fish -> possibleXyz.swim() } 

Некоторые вещи не позволяют использовать null проверку для умного приведения для последующего использования переменной. В приведенном выше примере используется локальная переменная, которая никоим образом не могла быть мутирована в потоке приложения, независимо от того, была ли val или var этой переменной не иметь мутаций в null . Но в других случаях, когда компилятор не может гарантировать анализ потока, это будет ошибкой:

 var nullableInt: Int? = ... public fun foo() { if (nullableInt != null) { // Error: "Smart cast to 'kotlin.Int' is impossible, because 'nullableInt' is a mutable property that could have been changed by this time" val nonNullableInt: Int = nullableInt } } 

Жизненный цикл переменной nullableInt не полностью виден и может быть назначен из других потоков, null проверка не может быть умной, отлитой в значение, не равное null . См. Раздел «Безопасные вызовы» ниже для обходного пути.

Другим случаем, которому нельзя доверять умный бросок, чтобы не мутировать, является свойство val для объекта, у которого есть пользовательский getter. В этом случае компилятор не имеет видимости того, что изменяет значение, и поэтому вы получите сообщение об ошибке:

 class MyThing { val possibleXyz: Xyz? get() { ... } } // now when referencing this class... val thing = MyThing() if (thing.possibleXyz != null) { // error: "Kotlin: Smart cast to 'kotlin.Int' is impossible, because 'px' is a property that has open or custom getter" thing.possiblyXyz.foo() } 

подробнее: Проверка нулевого условия