Kotlin и идиоматический способ писать, «если не null, else …», основанный на изменяемой ценности

Предположим, что у нас есть этот код:

class QuickExample { fun function(argument: SomeOtherClass) { if (argument.mutableProperty != null ) { doSomething(argument.mutableProperty) } else { doOtherThing() } } fun doSomething(argument: Object) {} fun doOtherThing() {} } class SomeOtherClass { var mutableProperty: Object? = null } 

В отличие от Java, где вас можно оставить в покое, чтобы беспокоиться о нулевой разыменовании во время выполнения, это не компилируется – совершенно правильно. Конечно, mutableProperty больше не может иметь значение null в «if».

Мой вопрос в том, что лучший способ справиться с этим?

Несколько вариантов очевидны. Без использования каких-либо новых функций языка Kotlin наиболее простым способом является, очевидно, копирование значения в область метода, которая не будет впоследствии изменяться.

Вот что:

 fun function(argument: SomeOtherClass) { argument.mutableProperty?.let { doSomething(it) return } doOtherThing() } 

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

Тогда есть такая возможность:

 fun function(argument: SomeOtherClass) { argument.mutableProperty.let { when { it != null -> { doSomething(it) } else -> { doOtherThing() } } } } 

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

Я что-то упускаю, и есть ли предпочтительная идиома для этого?

Я не верю, что существует действительно «короткий» способ достичь этого, однако вы можете просто использовать условное выражение внутри или let :

 with(mutableVar) { if (this != null) doSomething(this) else doOtherThing() } mutableVar.let { if (it != null) doSomething(it) else doOtherThing() } 

Это эквивалентно вашему заявлению when .

Всегда есть опция, которую вы описали, присваивая ее переменной:

 val immutable = mutableVar if (immutable != null) { doSomething(immutable) } else { doOtherThing() } 

который всегда является хорошим резервом в случае, например, вещи становятся слишком многословными.

Вероятно, это не очень хороший способ добиться этого, потому что только последний аргумент лямбда разрешен для использования вне () , поэтому указание двух не будет соответствовать синтаксису всех других стандартных функций.

Вы можете написать один, если вы не возражаете против этого (или если вместо этого вы передадите ссылки на методы):

 inline fun <T : Any, R> T?.ifNotNullOrElse(ifNotNullPath: (T) -> R, elsePath: () -> R) = let { if(it == null) elsePath() else ifNotNullPath(it) } 

Я бы использовал let с помощью оператора Элвиса .

 mutableProperty?.let { doSomething(it) } ?: doOtherThing() 

Из документа:

Если выражение слева от?: Не является нулевым, оператор elvis возвращает его, иначе он возвращает выражение вправо. Заметим, что выражение правой части оценивается только в том случае, если левая часть равна нулю.

Для блока кода после выражения правой стороны:

  mutableProperty?.let { doSomething(it) } ?: run { doOtherThing() doOtherThing() } 

добавьте пользовательскую встроенную функцию, как показано ниже:

 inline fun <T> T?.whenNull(block: T?.() -> Unit): T? { if (this == null) block() return this@whenNull } inline fun <T> T?.whenNonNull(block: T.() -> Unit): T? { this?.block() return this@whenNonNull } 

то вы можете написать код следующим образом:

 var nullableVariable :Any? = null nullableVariable.whenNonNull { doSomething(nullableVariable) }.whenNull { doOtherThing() } 
Intereting Posts
Котлин объясняет мне, что касается полей подкачки Невозможно добавить фрагменты с помощью функции расширения Kotlin API вызова Coroutine Опустить «Возврат» в Котлин нужен дополнительный код. Как это исправить? Создание публичного экземпляра частного внутреннего класса в Котлине IncompatibleClassChangeError: класс 'java.lang.VirtualMachineError' не реализует интерфейс 'java.lang.CharSequence' Можем ли мы использовать общие методы infix в Котлин? Объект и расширения приемника Kotlin Varargs Kotlin Java interop не работает должным образом Наследование Котлина Gradle не может разрешить плагин kotlin gradle 1.1.1 – InvalidAlgorithmParameterException Нулевые проверки не вставляются для типа reified, если параметр не является нулевым Kotlin падает на Android, когда выбранный вид элемента равен нулю Kotlin Тип несоответствия: предполагаемый тип View! но TextView ожидался Ошибка: не удается получить доступ к файлу класса KObject для kotlin.jvm.internal.KObject не найден