Что делает ?: делать в Котлине? (Оператор Элвиса)

98

Я не могу понять, что ?:, например, в этом случае

val list = mutableList ?: mutableListOf() 

и почему его можно изменить на это

val list = if (mutableList != null) mutableList else mutableListOf()
Jocas
источник
5
Верните левую сторону, если она не равна нулю, в противном случае верните правую сторону. Первое выражение - это краткое обозначение второго выражения. kotlinlang.org/docs/reference/null-safety.html#elvis-operator
Eugen Pechanec

Ответы:

115

TL; DR: Если результирующая ссылка на объект [первый операнд] не является null, она возвращается. В противном случае nullвозвращается значение второго операнда (которое может быть )


Оператор Elvis является частью многих языков программирования, например Kotlin, но также Groovy или C #. Я считаю определение Википедии довольно точным:

В некоторых языках компьютерного программирования оператор Элвиса ?: - это бинарный оператор, который возвращает свой первый операнд, если этот операнд есть true, а в противном случае оценивает и возвращает свой второй операнд. Это вариант тернарного условного оператора , ? :найденного в этих языках (и во многих других): оператор Элвиса является тернарным оператором с опущенным вторым операндом .

Для Котлина особенно актуально следующее:

Некоторые языки программирования имеют разную семантику для этого оператора. Вместо того, чтобы первый операнд приводил к логическому значению, он должен приводить к ссылке на объект . Если результирующей ссылки на объект нет null, она возвращается. В противном случае nullвозвращается значение второго операнда (которое может быть ).

Пример:

x ?: y // yields `x` if `x` is not null, `y` otherwise.
s1m0nw1
источник
3
Это действительно круто. Я никогда не думал, что elvis operatorможно свести к чему-то другому. отлично! И хорошее объяснение, спасибо!
sud007
88

Элвис Оператор представлен знак вопроса следует двоеточие: ?:и он может быть использован с этим синтаксисом:

first operand ?: second operand

Он позволяет вам писать целостный код и работает как таковой:

Если first operand не null , он будет возвращен. Если он равен нулю , то second operandбудет возвращено. Это можно использовать, чтобы гарантировать, что выражение не вернет значение NULL, поскольку вы предоставите значение, не допускающее значения NULL, если предоставленное значение равно NULL.


Например (в Котлине):

fun retrieveString(): String {    //Notice that this type isn't nullable
    val nullableVariable: String? = getPotentialNull() //This variable may be null
    
    return nullableVariable ?: "Secondary Not-Null String"
}

В этом случае, если вычисленное значение getPotentialNullне равно нулю, оно будет возвращено retrieveString; Если это ноль, второе выражение"Secondary Not-Null String" вместо него будет возвращено .

Также обратите внимание, что выражение в правой части оценивается только в том случае, если левая часть равна нулю. .

В Kotlin вы можете использовать любое выражение second operand, например, throw Exceptionвыражение

return nullVariable ?: throw IllegalResponseException("My inner function returned null! Oh no!")

Имя Элвис Оператор происходит от известного американского певца Элвиса Пресли . Его прическа напоминает вопросительный знак.

Элвис QuestionMark

Источник: Войда, И. Москала, М. Разработка Android с помощью Kotlin. 2017. Packt Publishing

ЛевКолман
источник
84
Плюс 1 за иллюстрацию мистера Пресли
s1m0nw1
7
? :) (смотри, как улыбается Элвис)
LeoColman
1
Через некоторое время я не могу понять, почему это называется «Оператор Элвиса». Ваша иллюстрация заставила меня понять, почему это называется «Оператор Элвиса». :)
Yohanes AI
правда ли история об Элвисе? ха-ха
Hillcow 01
@Kerooker Он не улыбается,?: | будет лучше ИМО.
Ahmed Galal
38

Это называется оператором Элвиса, и он делает ... В точности то, что вы описали в своем вопросе. Если его левая сторона -null значением, вместо этого он возвращает правую часть, что-то вроде запасного варианта. В противном случае он просто возвращает значение с левой стороны.

a ?: bэто просто сокращение от if (a != null) a else b.

Еще несколько примеров с типами:

val x: String? = "foo"
val y: String = x ?: "bar"      // "foo", because x was non-null    

val a: String? = null
val b: String = a ?: "bar"      // "bar", because a was null
zsmb13
источник
10
если вы пришли из java, это скорее сокращение для:a != null ? a : b
crgarridos
9

Давайте посмотрим на определение :

Когда у нас есть ссылка r, допускающая значение NULL, мы можем сказать: «Если r не равно NULL, используйте его, в противном случае используйте некоторое ненулевое значение x»:

Оператор ?:(Элвис) позволяет избежать многословия и делает ваш код действительно кратким.

Например, многие функции расширения коллекции возвращаются nullкак резервные.

listOf(1, 2, 3).firstOrNull { it == 4 } ?: throw IllegalStateException("Ups")

?:дает вам способ аккуратно справиться с резервным вариантом, даже если у вас есть несколько уровней отката. Если это так, вы можете просто связать операторы умножения Элвиса, как здесь:

val l = listOf(1, 2, 3)

val x = l.firstOrNull { it == 4 } ?: l.firstOrNull { it == 5 } ?: throw IllegalStateException("Ups")

Если бы вы выразили то же самое с помощью if else, было бы намного больше кода, который труднее читать.

Вилли Ментцель
источник
3

Можно просто сказать, что у вас две руки. Вы хотите знать, работает ли ваша левая рука сейчас? Если левая рука не работает, return emptyиначеbusy

Пример для Java:

private int a;
if(a != null){
    println("a is not null, Value is: "+a)
}
else{
    println("a is null")
}

Пример для Котлина:

val a : Int = 5
val l : Int = if (a != null) a.length else "a is null"
Ромман
источник
Люблю этот ответ. Слишком много чистого, чтобы понять.
Гк Мохаммад Эмон
2

В принципе, если левая часть Элвиса по какой-то причине возвращает ноль, вместо этого возвращается правая сторона.

т.е.

val number: Int? = null
println(number ?: "Number is null")

Таким образом, если число НЕ равно нулю , оно напечатает число, иначе напечатает «Число равно нулю».

Pauloaap
источник
1

Оператор elvis в Котлине используется для нулевой безопасности.

x = a ?: b

В приведенном выше коде xбудет присвоено значение, aесли a не равно, nullа bесли aесть null.

Ниже приведен эквивалентный код котлина без использования оператора elvis:

x = if(a == null) b else a
Абхишек А Удупа
источник
1

Небольшое дополнение, хотя это

X = A ?: B

Xвсе равно будет, nullесли оба Aи Bоценкаnull

Поэтому, если вы хотите Xвсегда быть non-null, убедитесь, что Bвсегда non-nullили Bвсегда оценивается, является non-nullли это функцией или выражением.

Уилсон
источник