【问题标题】:Kotlin Ternary Conditional OperatorKotlin 三元条件运算符
【发布时间】:2013-04-26 12:49:18
【问题描述】:

这个表达式在 Kotlin 中的等价物是什么?

a ? b : c

这不是 Kotlin 中的有效代码。

【问题讨论】:

  • 也许展示作业会让这一点更清楚。 "d = (a) ? b : c" 现在是 "d = if (a) b else c。同样适用于 when: "d = when { a -> b; c -> x; else ->d }"。我个人更喜欢 java/c/PERL 语法。
  • 是的,kotlin 的优秀设计者抛弃了 java 中最优雅的构造,取而代之的是 1) 可读性较差,2) 难以键入(即更多“样板代码”),以及 3 )对于初学者来说更难理解(将表达式与语句混为一谈)。我认为他们更改了三元组,因为...它是 java,根据他们的定义 必须 是坏的。
  • 在单行语句中使用 if-else 表达式类似于 Java 中的三元运算符。 Kotlin 不支持任何三元运算符。
  • 我已经使用 C# 和 Kotlin 多年了,但我仍然缺少 Kotlin 中的 ? : 运算符。它比if () else 构造更优雅、更短、更易读。这就是为什么这个问题的评分如此之高。

标签: kotlin conditional-operator


【解决方案1】:

在 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
  • 特别提及var v = a ?: b。这与var v = if(a != null) a else b 相同
  • @AdeelAnsari 不,它没有纠正。情况更糟。比较这个。 b + if (a) c else db + (c if (a) else d) 后者需要额外的括号。因为c没有被条件和else包围。
  • 这里是关于这个话题的一点讨论。 discuss.kotlinlang.org/t/ternary-operator/2116/141
【解决方案2】:

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

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 构造内联更具可读性

【讨论】:

  • 与问题无关,但为什么不使用 ?:elvis 运算符?第一个函数将替换为e.getMessage() ?: "unknown"。第二种可以表示为obj?.lastMessage?.timestamp ?: { Date() }()
  • @hotkey 没有特殊用途。从我的角度来看,它在链操作中看起来更一致,视觉上的噪音也更少,因为你不应该将结构包裹在括号中
  • @ruX elvis 运算符专门用于此目的,您的使用相当不寻常。
  • 虽然 ?: 很好,但我们不要在 Perl 的道路上走得太远。
【解决方案3】:

看看docs

在 Kotlin 中,if 是一个表达式,即它返回一个值。因此有 是没有三元运算符(条件?然后:否则), 因为普通的 if 在这个角色中可以正常工作。

【讨论】:

    【解决方案4】:

    您可以定义自己的Boolean 扩展函数,当Booleanfalse 时返回null,以提供类似于三元运算符的结构:

    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 &lt;T&gt; Boolean.then(param: () -&gt; T): T? = if (this) param() else null

    println(condition then { "yes" } ?: "no") 注意 lambda。它的内容计算应该推迟到我们确定conditiontrue

    这个看起来很笨拙,that is why there is high demanded request exist to port Java ternary operator into Kotlin

    【讨论】:

    【解决方案5】:

    when 替换了类 C 语言的 switch 运算符。最简单的形式是这样的

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

    【讨论】:

    • 是的,但是您显示的示例将when 作为语句,而不是表达式。与三元条件表达式更相关的比较是让每个分支都返回一个值,以便整个 when 表达式计算为一个值(就像三元条件表达式一样)。
    【解决方案6】:

    在 Kotlin 中,if 是一个表达式,即它返回一个值。所以 没有三元运算符(condition ? then : else),因为 普通 if 在这个角色中工作正常。 manual source from here

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

    【讨论】:

      【解决方案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"
      

      【讨论】:

      • 也许去掉 更好?中缀 fun or(falsy: T?) = if (flag) true else falsy
      • 但是添加 可以使它工作:(grade > 80) then null or "B"
      • 这真的很酷,我将使用它 :P 但请注意,除非我弄错了,否则每次调用它都会导致对象分配。没什么大不了的,但值得知道它不是零成本抽象。
      【解决方案8】:

      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】:

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

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

        b.takeIf { a } ?: c
        

        如果 c 是null,这将变得更短:

        b.takeIf { a }
        

        另请注意,Java 世界中典型的空检查,如 value != null ? value : defaultValue 在 ideomatic Kotlin 中仅转换为 value ?: defaultValue

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

        【讨论】:

        • b.takeIf { a } ?: cif (a) b else c 更短且可读性如何? Terneray 运算符肯定是 Kotlin 中缺少的功能,因为变量名和条件可能很长,并且会使您拆分错误的行
        • 还应注意takeIf 始终评估真实情况(此处为a)。如果 a 恰好为假,则不仅可能会无用地计算该表达式,而且您无法从智能转换中受益,例如 if (a is Int) { a + 3 }
        • @TheOperator,错了。 { a } 是一个惰性求值的 lambda。
        • 我写错了,应该是“总是评估真实情况(这里是b)”。但即使是 { a },虽然很懒惰,但也必须对 求值以确定表达式的结果。
        • b.takeIf { a } 在技术上等同于 b = a
        【解决方案10】:

        Java

        int temp = a ? b : c;
        

        相当于Kotlin:

        var temp = if (a) b else c
        

        【讨论】:

          【解决方案11】:

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

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

          在一些更复杂的场景中可以非常方便。老实说,它对我来说比if ... else ...更具可读性

          【讨论】:

            【解决方案12】:

            在 kotlin 中没有三元运算符,因为 if else 块返回值

            所以,你可以这样做: val max = if (a &gt; b) a else b 而不是java的max = (a &gt; b) ? b : c

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

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

            这里是 kotlin 文档的链接:Control Flow: if, when, for, while

            【讨论】:

              【解决方案13】:

              另一个简短的使用方法

              val value : String = "Kotlin"
              
              value ?: ""
              

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

              【讨论】:

                【解决方案14】:

                您可以在 Kotlin 中以多种方式做到这一点

                1. 使用如果

                  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
                  

                【讨论】:

                  【解决方案15】:

                  TL;DR

                  if (a) b else c
                  

                  ^ 是您可以使用的,而不是 Kotlin 语法不允许的三元运算符表达式 a ? b : c


                  在 Kotlin 中,许多控制语句,如ifwhen,甚至try,都可以用作表达式。因此,这些语句的结果可以分配给变量、从函数返回等。

                  语法上,不需要三元运算符

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

                  if (a) b else c
                  

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

                  我认为这个想法是前一个表达式更具可读性,因为每个人都知道ifelse 的作用,而? : 如果您不熟悉语法,则相当不清楚。

                  不过,我不得不承认,我经常错过更方便的三元运算符。


                  其他替代品

                  何时

                  在检查条件时,您可能还会看到 Kotlin 中使用的 when 构造。这也是一种以另一种方式表达 if-else 级联的方式。下面对应OTs的例子。

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

                  扩展

                  正如其他答案中的许多很好的示例 (Kotlin Ternary Conditional Operator) 所示,扩展也可以帮助解决您的用例。

                  【讨论】:

                    【解决方案16】:

                    使用以下中缀函数,我可以涵盖许多常见的用例,几乎可以在 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
                    

                    【讨论】:

                      【解决方案17】:

                      您可以在 Kotlin 中为此使用 if 表达式。在 Kotlin 中,if 是一个带有结果值的表达式。所以在 Kotlin 中我们可以写

                      fun max(a: Int, b: Int) = if (a > b) a else b
                      

                      在 Java 中我们可以实现相同的功能,但代码更大

                      int max(int a, int b) {
                      return a > b ? a : b
                      }
                      

                      【讨论】:

                        【解决方案18】:

                        当使用 apply() 时, let 在处理三元运算时看起来非常方便,因为它更优雅并且给你空间

                        val columns: List<String> = ...
                        val band = Band().apply {
                            name = columns[0]
                            album = columns[1]
                            year = columns[2].takeIf { it.isNotEmpty() }?.let { it.toInt() } ?: 0
                        }
                        

                        【讨论】:

                          【解决方案19】:

                          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 确实是我最喜欢的选项,非常优雅。
                          【解决方案20】:

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

                          • If else 作为表达式语句

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

                          • 猫王操作员

                          如果 ?: 左边的表达式不为空,elvis 运算符 返回它,否则将表达式返回到右边。笔记 仅当左侧表达式时才计算右侧表达式 边为空。

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

                          Reference docs

                          【讨论】:

                            【解决方案21】:

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

                            在 kotlin 中,如果您使用的是 ?: 它将像语句将返回 null 然后 ?: 0 它将采用 0 或您在这方面编写的任何内容.

                            【讨论】:

                              【解决方案22】:

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

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

                              当你真正可以使用这样的东西时(a 在这种情况下是布尔值):

                              when {
                                a -> b
                                else -> b
                              }
                              

                              【讨论】:

                              • 因为第一个在语义上清晰且易于阅读,即使他们不熟悉 Kotlin,而第二个则不熟悉。
                              • 嗯,你明白了,但是我不明白为什么 Kotlin 开发人员没有引入三元表达式
                              • 我认为 ? and : 与 nullable/ 类型声明相矛盾,而不是类型检查。除此之外,我看不出任何理由。我认为如果有内联 if-else 条件检查,肯定有人会考虑一下。让我们拭目以待未来的版本。
                              【解决方案23】:

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

                              kotlin 的另一个好概念是 Elvis Operator。您不需要每次都检查 null。

                              val l = b?.length ?: -1
                              

                              如果 b 不为空,则返回长度,否则执行右侧语句。

                              【讨论】:

                                【解决方案24】:

                                任务

                                让我们考虑以下示例:

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

                                我们在 Kotlin 中需要以下等价物:

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


                                解决方案 1.a。你可以在 Kotlin 中使用if-expression

                                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。感谢Elvis operator,使用Extension function可以减少代码:

                                return answer.bodyOrNull()?.string() ?: "wrong"
                                


                                解决方案 5。或者只使用when 运算符:

                                when (!answer.isSuccessful()) {
                                    parseInt(str) -> result = "wrong"
                                    else -> result = answer.body().string()
                                }
                                

                                【讨论】:

                                • 我在 Kotlin 的旅程中花了几十个小时,我很惊讶扩展方法是正确答案的频率。通常,我发现我不能使用?.?: 运算符,因为我想将Type? 传递给其他地方的方法,而不是调用it 上的方法。 (例如,将String? 传递给DateTimeFormatter. for parsing). In that case, we're back to an if (a != null) DateTimeFormatter.parse(s). But quick extension method 'turns it around' to s?/toSpecialDate()` 并且几乎总是有助于将细节排除在逻辑流程之外!我我爱 Kotlin :-)
                                【解决方案25】:

                                请记住 三元运算符Elvis 运算符Kotlin 中具有不同的含义,这与许多流行语言不同。执行expression? value1: value2 会在Kotlin 编译器中给你带来坏话,这与任何其他语言不同,因为official docs 中提到的Kotlin 中没有三元运算符。原因是 if、when 和 try-catch 语句本身返回值。

                                所以,expression? value1: value2 可以替换为

                                val max = if (a > b) print("选择一个") 别的 print("选择 b")

                                Kotlin 拥有的 Elvis 运算符,仅适用于可为空变量的情况,例如:

                                如果我执行value3 = value1 ?: value2 之类的操作,那么如果 value1null,则将返回 value2,否则返回 value1 将被退回。

                                更清晰的了解可以通过these answers实现。

                                【讨论】:

                                  【解决方案26】:

                                  Java 相当于三元运算符

                                  a ? b : c
                                  

                                  在 Kotlin 中是一个简单的 IF 在一行中

                                  if(a) b else c
                                  

                                  没有三元运算符(条件?然后:否则),因为 普通 if 在这个角色中工作正常。

                                  https://kotlinlang.org/docs/reference/control-flow.html#if-expression


                                  Null 比较的特殊情况

                                  您可以使用Elvis operator

                                  if ( a != null ) a else b
                                  // equivalent to
                                  a ?: b
                                  

                                  【讨论】:

                                    【解决方案27】:

                                    如果您不使用标准符号,您也可以使用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 的 lambda
                                    【解决方案28】:

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

                                    【讨论】:

                                    • 这个问题已经回答够了,最近没有更新。现在没有必要发布另一个与之前的答案没有区别的答案。
                                    【解决方案29】:

                                    如果有人需要隐式转换的三元运算符:

                                    /**'[_t]' for ternary operator*/
                                    @Suppress("FunctionName")
                                    @OptIn(ExperimentalContracts::class)
                                    fun <T> _t(bool: Boolean, onTrue: T, onFalse: T): T
                                    {
                                        contract { returns() implies bool }
                                        return if (bool) onTrue else onFalse
                                    }
                                    

                                    虽然不确定这有多大用处

                                    【讨论】:

                                      【解决方案30】:

                                      fun max(x:Int,y:Int) : String = if (x>y) "max = $x" else "max = $y"

                                      内联函数

                                      【讨论】:

                                        猜你喜欢
                                        • 2019-01-18
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 2019-07-14
                                        • 2012-02-22
                                        • 2013-06-06
                                        • 2023-04-11
                                        • 2015-05-20
                                        • 2020-01-18
                                        相关资源
                                        最近更新 更多