Intereting Posts
Можно ли связать член класса в кодеин? Имеет ли Kotlin функцию «перечисления», такую ​​как Python? Как прочитать ряд элементов под дочерним узлом в Firebase с использованием FirebaseAdapter Переназначение переменных посредством деструктурирования Как инициализировать виджеты в android с помощью kotlin Котлин: ссылка на метод не работает? Вызов функции более высокого порядка Kotlin из Java Как разобрать LocalDateTime из RestController в Котлине Объясните, почему показано предупреждение. Не отмечен ли источник-источник.readArrayList (data !!. JavaClass.classLoader) как ArrayList <Data>? Импортировать библиотеки зависимостей в терминале kotlinc Кинжал 2 Именован не может быть предоставлен без метода @Provides Какие функции Kotlin недоступны в статически скомпилированном Groovy? Как подключить источники для Kotlin в Android Studio? Отменить возвращаемое значение для возврата Unit? Kotlin проверяет, требует ли функция экземпляра

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() }