Ответы:
В Kotlin if
заявления являются выражениями. Таким образом, следующий код эквивалентен:
if (a) b else c
Здесь важно различие между выражением и утверждением. В Java / C # / JavaScript if
формирует утверждение, означающее, что оно не преобразуется в значение. Конкретнее, вы не можете присвоить его переменной.
// Valid Kotlin, but invalid Java/C#/JavaScript
var v = if (a) b else c
Если вы говорите на языке, на котором if
есть утверждение, это может показаться неестественным, но это чувство скоро должно исчезнуть.
when
.
x = a==b
b + if (a) c else d
vs. b + (c if (a) else d)
Последний требует дополнительных скобок. потому что c
не включено в условие и else
.
Вы можете определить свою собственную Boolean
функцию расширения , которая возвращается , null
когда Boolean
является false
обеспечить структуру , подобную троичной оператора:
infix fun <T> Boolean.then(param: T): T? = if (this) param else null
Это сделало бы a ? b : c
выражение переводящим a then b ?: c
, вот так:
println(condition then "yes" ?: "no")
Обновление: Но чтобы сделать еще один Java-подобный условный переход, вам понадобится что-то подобное
infix fun <T> Boolean.then(param: () -> T): T? = if (this) param() else null
println(condition then { "yes" } ?: "no")
обратите внимание на лямбду. расчет его содержание должно быть отложено , пока мы не уверены , condition
являетсяtrue
Это выглядит неуклюже, поэтому существует высокий спрос на портирование троичного оператора Java в Котлин
infix inline fun<T> Boolean.then(param: ()->T):T? = if(this) param() else null
true then { null } ?: "not-null"
?:
оператор здесь elvis-operator
: kotlinlang.org/docs/reference/null-safety.html#elvis-operator
if (a) b else c
это то, что вы можете использовать вместо выражения троичного оператора a ? b : c
.
В Котлин, многие управляющие операторы в том числе if
, when
или даже try
могут быть использованы в качестве выражения . Это означает, что у них может быть результат, который можно присвоить переменной, вернуть из функции и т. Д.
В результате выражений Котлина языку на самом деле не нужен троичный оператор .
if (a) b else c
это то, что вы можете использовать вместо выражения троичного оператора a ? b : c
.
Я думаю, что идея в том, что первое выражение более читабельно, так как все знают, что ifelse
делает, тогда ? :
как довольно непонятно, если вы уже не знакомы с синтаксисом.
Тем не менее, я должен признать, что мне часто не хватает более удобного троичного оператора.
Другие альтернативы
когда
Вы также можете увидеть when
конструкции, используемые в Kotlin при проверке условий. Это также способ выразить каскад if-else альтернативным способом. Следующее соответствует примеру OTs.
when(a) {
true -> b
false -> c
}
расширения
Как показывают многие хорошие примеры ( Kotlin Ternary Conditional Operator ) в других ответах, расширения также могут помочь в решении вашего варианта использования.
Для себя я использую следующие функции расширения:
fun T?.or<T>(default: T): T = if (this == null) default else this
fun T?.or<T>(compute: () -> T): T = if (this == null) compute() else this
Первый возвращает возвращаемое значение по умолчанию, если объект равен нулю. Второй будет оценивать выражение, предоставленное в лямбда в том же случае.
Применение:
1) e?.getMessage().or("unknown")
2) obj?.lastMessage?.timestamp.or { Date() }
Лично для меня код выше более if
читабелен, чем встроенная конструкция
e.getMessage() ?: "unknown"
. Второе можно выразить какobj?.lastMessage?.timestamp ?: { Date() }()
Java-эквивалент троичного оператора
a ? b : c
простой IF в Котлине в одну строку
if(a) b else c
нет троичного оператора (условие? тогда: еще), потому что обычный, если работает отлично в этой роли.
https://kotlinlang.org/docs/reference/control-flow.html#if-expression
Особый случай для нулевого сравнения
Вы можете использовать оператор Элвиса
if ( a != null ) a else b
// equivalent to
a ?: b
В котлине нет троичного оператора , так как if else
блок возвращает значение
Итак, вы можете сделать:
val max = if (a > b) a else b
вместо Javamax = (a > b) ? b : c
Мы также можем использовать when
конструкцию, она также возвращает значение:
val max = when(a > b) {
true -> a
false -> b
}
Вот ссылка на документацию kotlin: Поток управления: если, когда, для, пока
В Kotlin
if
это выражение, т.е. оно возвращает значение. Поэтому нет тройного оператора(condition ? then : else)
, потому что обычный if отлично работает в этой роли. ручной источник отсюда
// Traditional usage
var max = a
if (a < b) max = b
// With else
var max: Int
if (a > b) {
max = a
} else {
max = b
}
// As expression
val max = if (a > b) a else b
Некоторые угловые случаи, не упомянутые в других ответах.
С момента появления takeIf в Kotlin 1.1 троичный оператор a ? b : c
также может быть выражен так:
b.takeIf { a } ?: c
Это становится еще короче, если с null
:
b.takeIf { a }
Также обратите внимание, что типичные в мире Java проверки value != null ? value : defaultValue
на ноль, такие как перевод в идеологическом Kotlin, просто value ?: defaultValue
.
Подобное a != null ? b : c
можно перевести на a?.let { b } ?: c
.
b.takeIf { a } ?: c
короче и читабельнее, чем if (a) b else c
? Тернерный оператор, безусловно, отсутствует в Kotlin, так как имена переменных и условия могут быть длинными, и вы можете разбить строку, что плохо
takeIf
всегда оценивает истинный случай (здесь a
). Мало того, что это выражение может быть вычислено бесполезно, если оно a
окажется ложным, но вы не сможете извлечь выгоду из умных приведений а-ля if (a is Int) { a + 3 }
.
{ a }
это лениво оцененная лямбда.
b
)". Но даже { a }
, будучи ленивым, нужно оценить, чтобы определить результат выражения.
Ява
int temp = a ? b : c;
Эквивалент Котлину:
var temp = if (a) b else c
ЗАДАЧА :
Давайте рассмотрим следующий пример:
if (!answer.isSuccessful()) {
result = "wrong"
} else {
result = answer.body().string()
}
return result
Нам нужен следующий эквивалент в Kotlin:
return (! answer.isSuccessful ())
?
«неправильно»:
answer.body (). string ()
РЕШЕНИЯ :
1.а . Вы можете использовать if-expression
в Kotlin:
return if (!answer.isSuccessful()) "wrong" else answer.body().string()
1б . Может быть намного лучше, если вы перевернете это if-expression
(давайте сделаем это без not
):
return if (answer.isSuccessful()) answer.body().string() else "wrong"
2 . Оператор Котлина Элвис ?:
может сделать работу еще лучше:
return answer.body()?.string() ?: "wrong"
3 . Или используйте Extension function
для соответствующего Answer
класса:
fun Answer.bodyOrNull(): Body? = if (isSuccessful()) body() else null
4 . Используя Extension function
вы можете уменьшить код благодаря Elvis operator
:
return answer.bodyOrNull()?.string() ?: "wrong"
5 . Или просто используйте when
оператор:
when (!answer.isSuccessful()) {
parseInt(str) -> result = "wrong"
else -> result = answer.body().string()
}
Надеюсь это поможет.
когда заменяет оператор переключения C-подобных языков. В простейшем виде это выглядит так
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> {
print("x is neither 1 nor 2")
}
}
when
форму выражения, а не выражения. Более уместным сравнением с троичными условными выражениями было бы, чтобы каждая ветвь возвращала значение, такое, чтобы целое выражение выражало значение (как это происходит с троичными условными выражениями).
В Котлине нет троичного оператора. Это кажется проблематичным на первый взгляд. Но думаю, что мы можем сделать это с помощью встроенного оператора if else, потому что это выражение здесь. Просто мы должны сделать -
var number = if(n>0) "Positive" else "Negetive"
Здесь мы можем еще, если заблокировать слишком много, сколько нам нужно. Подобно-
var number = if(n>0) "Positive" else if(n<0) "Negative" else "Zero"
Так что эта строка настолько проста и намного удобочитаемее, чем троичный оператор. когда мы используем более одного троичного оператора в Java, это кажется ужасным. Но здесь у нас есть четкий синтаксис. даже мы можем написать это в несколько строк тоже.
Вы можете использовать var a= if (a) b else c
вместо троичного оператора.
Другая хорошая концепция kotlin - оператор Элвиса. Вам не нужно проверять ноль каждый раз.
val l = b?.length ?: -1
Это вернет длину, если b не равно нулю, иначе он выполнит оператор правой части.
как цитировал Дрю Ноакс, kotlin использует оператор if в качестве выражения, поэтому тернарный условный оператор больше не нужен,
но с помощью функции расширения и инфиксной перегрузки вы можете реализовать это самостоятельно, вот пример
infix fun <T> Boolean.then(value: T?) = TernaryExpression(this, value)
class TernaryExpression<out T>(val flag: Boolean, val truly: T?) {
infix fun <T> or(falsy: T?) = if (flag) truly else falsy
}
затем используйте это так
val grade = 90
val clazz = (grade > 80) then "A" or "B"
Еще один интересный подход будет использовать when
:
when(a) {
true -> b
false -> b
}
Может быть весьма удобно в некоторых более сложных сценариях. И, честно говоря, это более читабельно для меня, чемif ... else ...
Вы можете сделать это по-разному в Kotlin
Используя если
if(a) b else c
Использование когда
when (a) {
true -> print("value b")
false -> print("value c")
else -> {
print("default return in any other case")
}
}
Нулевая безопасность
val a = b ?: c
В Котлине нет никакой троичной операции, но есть несколько забавных способов обойти это. Как отмечали другие, прямой перевод на Kotlin будет выглядеть так:
val x = if (condition) result1 else result2
Но лично я думаю, что это может стать немного загроможденным и трудным для чтения. Есть несколько других опций, встроенных в библиотеку. Вы можете использовать takeIf {} с оператором elvis:
val x = result1.takeIf { condition } ?: result2
Здесь происходит то, что команда takeIf {} возвращает либо ваш result1, либо null, а оператор elvis обрабатывает нулевую опцию. Есть несколько дополнительных опций, takeUnless {}, например:
val x = result1.takeUnless { condition } ?: result2
Язык понятен, вы знаете, что он делает.
Если это часто используемое условие, вы также можете сделать что-нибудь интересное, например, использовать метод встроенного расширения. Давайте предположим, что мы хотим отслеживать счет игры как, например, Int, и мы хотим всегда возвращать 0, если данное условие не выполняется:
inline fun Int.zeroIfFalse(func: () -> Boolean) : Int = if (!func.invoke()) 0 else this
Хорошо, это выглядит некрасиво. Но посмотрим, как это выглядит, когда он используется:
var score = 0
val twoPointer = 2
val threePointer = 3
score += twoPointer.zeroIfFalse { scoreCondition }
score += threePointer.zeroIfFalse { scoreCondition }
Как вы можете видеть, Kotlin предлагает большую гибкость при выборе способа выражения вашего кода. Есть бесчисленное множество вариантов моих примеров и, возможно, способов, которые я еще даже не обнаружил. Надеюсь, это поможет!
takeIf
это действительно мой любимый вариант, очень элегантный.
Помните, что тернарный оператор и оператор Элвиса имеют разные значения в котлинском языке, в отличие от многих популярных языков. Выполнение expression? value1: value2
дало бы вам плохие слова от компилятора Kotlin , в отличие от любого другого языка, поскольку в Kotlin нет ни одного троичного оператора, как упомянуто в официальных документах . Причина в том, что операторы if, when и try-catch сами возвращают значения.
Таким образом, делать expression? value1: value2
можно заменить
val max = if (a> b) print («Выбрать a») else print («Выбрать b»)
Оператор Элвиса, который есть у Котлина , работает только в случае обнуляемых переменных, например:
Если я что - то вроде
value3 = value1 ?: value2
то , если значение1 является нулевым , то значение2 будет возвращен в противном случае значение1 будут возвращены.
Из этих ответов можно достичь более четкого понимания .
Вы можете использовать if
выражение для этого в Kotlin. В Kotlin if
есть выражение со значением результата. Так что в Котлине мы можем написать
fun max(a: Int, b: Int) = if (a > b) a else b
и в Java мы можем добиться того же, но с большим кодом
int max(int a, int b) {
return a > b ? a : b
}
Если вам не нужно использовать стандартную нотацию, вы также можете создать / смоделировать ее, используя infix, примерно так:
создайте класс для хранения вашей цели и результата:
data class Ternary<T>(val target: T, val result: Boolean)
создать некоторые инфиксные функции для симуляции троичной операции
infix fun <T> Boolean.then(target: T): Ternary<T> {
return Ternary(target, this)
}
infix fun <T> Ternary<T>.or(target: T): T {
return if (this.result) this.target else target
}
Тогда вы сможете использовать его так:
val collection: List<Int> = mutableListOf(1, 2, 3, 4)
var exampleOne = collection.isEmpty() then "yes" or "no"
var exampleTwo = (collection.isNotEmpty() && collection.contains(2)) then "yes" or "no"
var exampleThree = collection.contains(1) then "yes" or "no"
Еще один короткий подход к использованию
val value : String = "Kotlin"
value ?: ""
Здесь kotlin сам проверяет нулевое значение, и если он равен нулю, он передает пустое строковое значение.
Зачем использовать что-то вроде этого:
when(a) {
true -> b
false -> b
}
когда вы можете использовать что-то вроде этого ( a
в данном случае это логическое значение):
when {
a -> b
else -> b
}
? and :
противоречит декларации типа nullable / type, а не проверке типа. Кроме этого я не вижу никакой причины. Я думаю, что кто-то определенно мог бы подумать, если есть встроенная проверка условий if-else. Давайте подождем и посмотрим в будущих версиях.
При работе с apply (), пусть кажется очень удобным при работе с троичными операциями, так как это более элегантно и дает вам место
val columns: List<String> = ...
val band = Band().apply {
name = columns[0]
album = columns[1]
year = columns[2].takeIf { it.isNotEmpty() }?.let { it.toInt() } ?: 0
}
Со следующими инфиксными функциями я могу охватить многие распространенные случаи использования почти так же, как это можно сделать в Python:
class TestKotlinTernaryConditionalOperator {
@Test
fun testAndOrInfixFunctions() {
Assertions.assertThat(true and "yes" or "no").isEqualTo("yes")
Assertions.assertThat(false and "yes" or "no").isEqualTo("no")
Assertions.assertThat("A" and "yes" or "no").isEqualTo("yes")
Assertions.assertThat("" and "yes" or "no").isEqualTo("no")
Assertions.assertThat(1 and "yes" or "no").isEqualTo("yes")
Assertions.assertThat(0 and "yes" or "no").isEqualTo("no")
Assertions.assertThat(Date() and "yes" or "no").isEqualTo("yes")
@Suppress("CAST_NEVER_SUCCEEDS")
Assertions.assertThat(null as Date? and "yes" or "no").isEqualTo("no")
}
}
infix fun <E> Boolean?.and(other: E?): E? = if (this == true) other else null
infix fun <E> CharSequence?.and(other: E?): E? = if (!(this ?: "").isEmpty()) other else null
infix fun <E> Number?.and(other: E?): E? = if (this?.toInt() ?: 0 != 0) other else null
infix fun <E> Any?.and(other: E?): E? = if (this != null) other else null
infix fun <E> E?.or(other: E?): E? = this ?: other
В Котлине нет троичного оператора, наиболее закрытыми являются следующие два случая,
val a = true if(a) print("A is true") else print("A is false")
Если выражение слева от?: Не равно нулю, оператор elvis возвращает его, в противном случае возвращает выражение справа. Обратите внимание, что выражение в правой части вычисляется только в том случае, если значение в левой части равно нулю.
val name = node.getName() ?: throw IllegalArgumentException("name expected")
пример: var energy: Int = data? .get (position) ?. energy? .toInt ()?: 0
В kotlin, если вы используете ?: Это будет работать так, как если бы инструкция вернула ноль тогда ?: 0 это займет 0 или что-то еще, что вы написали на этой стороне.
В Kotlin вы можете использовать троичную операцию следующим образом: val x = if(a) "add b" else "add c"
После некоторых исследований других идей я получил следующий троичный оператор:
infix fun <T : Any> Boolean.yes(trueValue: T): T? = if (this) trueValue else null
infix fun <T : Any> T?.no(falseValue: T): T = this ?: falseValue
Пример (запустить здесь ):
fun main() {
run {
val cond = true
val result = cond yes "True!" no "False!"
println("ternary test($cond): $result")
}
run {
val cond = false
val result = cond yes "True!" no "False!"
println("ternary test($cond): $result")
}
}
Эта версия свободно и не конфликтует с оператором null coalescing.
then
вместо имени он назван yes
.