Kotlin三元条件运算符


Answers:


616

在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,这似乎很不自然,但这种感觉很快就会消失。


57
另外,您可以使用when
2013年

5
只需添加一下,如果它是布尔表达式,您甚至可以使用x = a==b
gnomeria

2
@MikeRylander我已经扩展了答案,以使其明确。感谢您指出了这一点。
Drew Noakes

1
@AdeelAnsari不,它没有纠正。更糟 比较一下。b + if (a) c else dvs. b + (c if (a) else d)后者需要附加括号。因为c没有被条件和包围else
Naetmul

1
这里是有关此主题的一些讨论。describe.kotlinlang.org/t/ternary-operator/2116/141
F. Norbert

70

你可以定义自己的Boolean扩展函数返回nullBooleanfalse提供类似于三元运算符的结构:

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") 注意lambda。它的内容计算应该推迟到我们确定conditiontrue

这看起来很笨拙,这就是为什么存在将Java三元运算符移植到Kotlin的高要求的原因


1
infix inline fun<T> Boolean.then(param: ()->T):T? = if(this) param() else null
nullbyte '17

3
使用<T:Any>,否则将true then { null } ?: "not-null"
无法

顺便说一句,?:这里的操作员是elvis-operatorkotlinlang.org/docs/reference/null-safety.html#elvis-operator
Eric Wang

64

TL; DR

if (a) b else c

是您可以用来代替三元运算符的表达式a ? b : c


在Kotlin中,许多控制语句包括ifwhen甚至try可以用作表达式。这意味着它们可以具有可以分配给变量,从函数返回等的结果。

从句法上讲,不需要三元运算符

由于Kotlin的表达,该语言实际上并不需要三元运算符

if (a) b else c

是您可以用来代替三元运算符的表达式a ? b : c

我认为这样的想法是,由于每个人都知道它的含义,因此前一个表达式更具可读性ifelse,而? :如果您还不熟悉该语法,则还不清楚。

尽管如此,我不得不承认我经常想念更方便的三元运算符。


其他选择

什么时候

when检查条件时,您可能还会看到Kotlin中使用的构造。这也是一种以其他方式表示if-else级联的方式。以下对应于OT的示例。

when(a) {
    true -> b
    false -> c
}

扩展名

正如其他答案中许多好的示例(Kotlin三元条件运算符)所示,扩展也可以帮助解决您的用例。


36

我自己使用以下扩展功能:

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

如果对象等于null,则第一个将返回提供的默认值。其次,将评估在相同情况下lambda中提供的表达式。

用法:

1) e?.getMessage().or("unknown")
2) obj?.lastMessage?.timestamp.or { Date() }

就我个人而言,以上代码比if构造内联更具可读性


34
这并不是说相关的问题,但为什么不能用,在猫王操作?第一个函数将替换为e.getMessage() ?: "unknown"。第二个可以表示为obj?.lastMessage?.timestamp ?: { Date() }()
热键

1
@hotkey没有特殊用途。从我的角度来看,由于您不应该将结构打包在括号中,因此链条操作中的外观看起来更加一致且噪音较小
ruX 15'Jul

14
@ruX elvis运算符专门用于此操作,您的使用非常少见。
杰森·米纳德

6
尽管?:很好,但我们不要太过深入Perl。
理查德·黑文


28

没有三元运算符在科特林,作为if else块返回值

因此,您可以: val max = if (a > b) a else b 用Java代替max = (a > b) ? b : c

我们还可以使用when构造,它也返回值:

val max = when(a > b) {
    true -> a
    false -> b
}

这是kotlin文档的链接:控制流:是否,何时,何时,何时


27

在Kotlin中,if是一个表达式,即它返回一个值。因此没有三元运算符(condition ? then : else),因为普通的如果在该角色中工作良好。 这里的手册来源

// 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

26

其他答案未提及的一些极端情况。

由于takeIfKotlin 1.1中出现,三元运算符a ? b : c也可以这样表示:

b.takeIf { a } ?: c

如果c为null

b.takeIf { a }

还要注意,在Java世界中,典型的null检查(例如,value != null ? value : defaultValue将意识形态Kotlin中的null检查转换为just)value ?: defaultValue

类似的a != null ? b : c可以翻译为a?.let { b } ?: c


6
b.takeIf { a } ?: c比它更短,更易读if (a) b else c?Terneray运算符无疑是Kotlin中缺少的功能,因为变量名和条件可能很长,使您
分界

1
还应该注意的是,takeIf总是评估真实情况(在此处a)。如果a碰巧是假的,那么该表达式不仅会被无用地计算,而且您无法从智能转换àla中受益if (a is Int) { a + 3 }
TheOperator'Aug

@TheOperator,错了。{ a }是惰性评估的lambda。
Vadzim '18年

1
我写错了,应该是“总是评估真实情况(在这里b)”。但是,即使是{ a }懒惰的人,也必须对其求值以确定表达式的结果。
TheOperator '18

24

看看文档

在Kotlin中,if是一个表达式,即它返回一个值。因此,没有三元运算符(条件?then:else),因为普通if在此角色下工作良好。



12

任务

让我们考虑以下示例:

if (!answer.isSuccessful()) {
    result = "wrong"
} else {
    result = answer.body().string()
}
return result

我们在Kotlin中需要以下等效项:

返回(!answer.isSuccessful()) ? “错误”的 : answer.body()。string()


解决方案

1.A。您可以if-expression在Kotlin中使用:

return if (!answer.isSuccessful()) "wrong" else answer.body().string()

1.B。翻转此按钮会更好if-expression(让我们不用not):

return if (answer.isSuccessful()) answer.body().string() else "wrong"

2。Kotlin的Elvis操作员?:可以做得更好:

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

希望这可以帮助。


11

when替换类C语言的switch运算符。以最简单的形式看起来像这样

when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> {
        print("x is neither 1 nor 2")
    }
}

3
是的,但您显示的示例仅when作为声明而不是表达式。与三元条件表达式的更相关的比较是使每个分支都返回一个值,以使整个when表达式的值均等于一个值(如三元条件表达式一样)。
Drew Noakes

9

Kotlin中没有三元运算符。乍看起来似乎有问题。但是请认为我们可以使用内联if else语句来完成此操作,因为这是此处的表达式。只需我们要做-

var number = if(n>0) "Positive" else "Negetive"

在这里,我们可以根据需要阻塞太多。喜欢-

var number = if(n>0) "Positive" else if(n<0) "Negative" else "Zero"

因此,这条线比三元运算符简单易读。当我们在Java中使用多个三元运算符时,这似乎很可怕。但是这里我们有一个清晰的语法。即使我们也可以将其写成多行。


9

您可以var a= if (a) b else c代替三元运算符使用。

Kotlin的另一个很好的概念是猫王操作员。您无需每次都检查null。

val l = b?.length ?: -1

如果b不为null,它将返回length,否则将执行右边的语句。


7

正如Drew Noakes所引用的那样,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"

也许删除<T>更好缀乐趣或(falsy:T)?= IF(标志)真正否则falsy
独奏

1
但是添加<T>可以使其起作用:(等级> 80)然后为null或“ B”
独奏

这真的很酷,我将使用它:P但是要注意,除非我弄错了,否则它将在每次调用时引起对象分配。这不是什么大问题,但值得一提的是它不是零成本的抽象。
亚当

6

另一种有趣的方法是使用when

when(a) {
  true -> b
  false -> b
}

在某些更复杂的场景中可以非常方便。老实说,对我而言,它比if ... else ...


6

您可以在科特林做很多事情

  1. 使用if

    if(a) b else c
  2. 使用时间

    when (a) { 
        true -> print("value b") 
        false -> print("value c") 
        else -> {  
            print("default return in any other case") 
        } 
    }
  3. 空安全

    val a = b ?: c

5

Kotlin中没有三元运算,但是有一些有趣的方法可以解决此问题。正如其他人指出的那样,直接翻译成Kotlin会像这样:

val x = if (condition) result1 else result2

但是,就我个人而言,我认为这可能会有些混乱并且难以阅读。库中还内置了其他一些选项。您可以将takeIf {}与Elvis运算符配合使用:

val x = result1.takeIf { condition } ?: result2

发生的情况是takeIf {}命令返回result1或null,而elvis运算符处理null选项。还有一些其他选项,例如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确实是我最喜欢的选择,非常优雅。
哈维尔·门登萨(JavierMendonça)

4

请记住,与许多流行语言不同,三元运算符猫王运算符Kotlin中具有不同的含义。这样做expression? value1: value2会使Kotlin编译器给您带来不好的单词,这与任何其他语言都不一样,因为Kotlin中没有官方文档中提到的三元运算符。原因是if,when和try-catch语句本身返回值。

因此,expression? value1: value2可以将其替换为

val max = if(a> b)print(“ Choose a”)else print(“ Choose b”)

Elvis操作符科特林了,只能在可空变量前的情况:

如果我做类似的事情,value3 = value1 ?: value2那么如果value1null,则将返回value2,否则将返回value1

这些答案中可以获得更清晰的理解。


3

您可以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
}

2

如果您不使用标准符号,也可以使用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"

为了使其完全等同于实际的三元运算符,目标值还可以是提供T的λ
Aran的老人

1

另一个简短的使用方法

val value : String = "Kotlin"

value ?: ""

在这里,kotlin本身会检查null值,如果为null,则它将传递空字符串值。


1

为什么要使用这样的东西:

when(a) {
  true -> b
  false -> b
}

当您实际上可以使用这样的东西时(a在这种情况下为布尔值):

when {
  a -> b
  else -> b
}

1
因为第一个在语义上是清晰的,即使其他人对wotlin不熟悉,其他人也很容易理解,而第二个则不是。
mc01

1
嗯,您已经明白了,但是我不明白为什么Kotlin开发人员没有引入三元表达式
ZZ

我认为? and :与nullable /类型声明而不是类型检查相矛盾。除此之外,我看不出任何原因。我想如果有内联的if-else条件检查,肯定有人会考虑一下。让我们拭目以待。
bh4r4th

1

当使用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
}

0

使用以下infix函数,我可以像在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

0

Kotlin中没有三元运算符,最封闭的是以下两种情况,

  • 如果作为表达式语句

val a = true if(a) print("A is true") else print("A is false")

  • 猫王算子

如果?:左侧的表达式不为null,则elvis运算符将其返回,否则它将返回右侧的表达式。注意,仅当左侧为null时,才对右侧表达式求值。

 val name = node.getName() ?: throw IllegalArgumentException("name expected")

参考文件


0

例如: var energy:Int = data?.get(position)?. energy?.toInt()?:0

在kotlin中,如果您使用 ?: 它将像语句将返回null,然后 ?:0一样工作,它将花费0或您编写此面的任何内容。


-1

在Kotlin中,您可以使用以下三元运算: val x = if(a) "add b" else "add c"


1
这个问题已经得到足够的答案,并且最近没有更新。现在无需发布与以前的答案相同的另一个答案。
爆头

-2

在对其他想法进行了一些研究之后,我得出了以下三元运算符:

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

该版本很流畅,并且与空合并运算符不冲突。


这与deviant的答案(以then代替)相同yes
Ry-

@Ry是的,我不确定他们是否是同一个人,但是将infix方法与可选参数一起使用的想法来自Kotlin论坛。我没有看到的是我想出的“ no”方法,因为我发现空合并运算符的内联用法令人困惑,因为问号位于“ then value”之后,而不是像大多数语言中那样的条件。
布莱恩·瓦格纳
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.