【问题标题】:What does ?: do in Kotlin? (Elvis Operator)?: 在 Kotlin 中做什么? (猫王操作员)
【发布时间】:2018-06-23 12:00:54
【问题描述】:

我不知道?: 在这种情况下做了什么

val list = mutableList ?: mutableListOf() 

为什么可以修改成这个

val list = if (mutableList != null) mutableList else mutableListOf()

【问题讨论】:

标签: kotlin


【解决方案1】:

TL;DR:如果结果对象引用 [第一个操作数] 不是 null,则返回它。否则返回第二个操作数(可能是null)的值。另外,如果返回null,操作符可以抛出异常。


Elvis 运算符 是许多编程语言的一部分,例如Kotlin 还有 Groovy 或 C#。 我发现Wikipedia 的定义非常准确:

在某些计算机编程语言中,Elvis 运算符?: 是一个二元运算符,如果该操作数是true,则返回其第一个操作数,否则计算和返回它的第二个操作数。它是一种三元条件运算符的变体? :,在这些语言(以及许多其他语言)中都可以找到:Elvis 运算符是 省略了第二个操作数的三元运算符 .

对于 Kotlin 来说尤其如此:

一些计算机编程语言对该运算符有不同的语义。 不是第一个操作数必须产生一个布尔值,它必须产生一个对象引用。如果结果对象引用不是null,则返回它。否则返回第二个操作数的值(可能是null)。如果第二个操作数为 null,则操作符也可以抛出异常。

一个例子:

x ?: y // yields `x` if `x` is not null, `y` otherwise.
x ?: throw SomeException() // yields `x` if `x` is not null, throws SomeException otherwise

【讨论】:

    【解决方案2】:

    Elvis Operator 由一个问号后跟一个冒号表示:?:,它可以与以下语法一起使用:

    first operand ?: second operand
    

    它使您可以编写简洁的代码,并且可以这样工作:

    如果first operand 不为空,则返回。如果为空,则返回second operand。这可用于保证表达式不会返回 null 值,因为如果提供的值为 null,您将提供一个不可为 null 的值。


    例如(在 Kotlin 中):

    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的计算值不为null,则由retrieveString返回;如果为null,则返回第二个表达式"Secondary Not-Null String"

    另请注意,如果左侧为 null,则评估右侧表达式。

    在 Kotlin 中,您可以使用任何表达式作为 second operand,例如 throw Exception 表达式

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

    Elvis Operator 这个名字来源于美国著名歌手Elvis Presley。他的发型像一个问号

    资料来源:Wojda、I. Moskala、M. 使用 Kotlin 进行 Android 开发。 2017. Packt 出版

    【讨论】:

      【解决方案3】:

      这被称为Elvis operator,它确实......正是您在问题中所描述的。如果它的左侧是 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
      

      【讨论】:

      • 如果你来自java,它更像是:a != null ? a : b
      【解决方案4】:

      我们来看看defintion

      当我们有一个可为空的引用 r 时,我们可以说“如果 r 不为空,使用 它,否则使用一些非空值 x":

      ?: (Elvis) 运算符避免冗长,使您的代码非常简洁。

      例如,许多集合扩展函数返回 null 作为后备。

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

      ?: 为您提供了一种优雅地处理后备情况的方法,即使您有多层后备。如果是这样,您可以简单地链接乘法 Elvis 运算符,如下所示:

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

      如果你用 if else 来表达同样的意思,那将是更多难以阅读的代码。

      【讨论】:

        【解决方案5】:

        简单地说,你有两只手。你想知道,你的左手现在还在工作吗?如果左手不工作,returnempty 否则busy

        Java 示例:

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

        Kotlin 示例:

        val a : Int = 5
        val l : Int = if (a != null) a.length else "a is null"
        

        【讨论】:

          【解决方案6】:

          Kotlin 中的 elvis 运算符用于 null 安全性。

          x = a ?: b
          

          在上面的代码中,如果 a 不是 nullb 如果 anullx 将被分配 a 的值。

          不使用 elvis 运算符的等效 kotlin 代码如下:

          x = if(a == null) b else a
          

          【讨论】:

            【解决方案7】:

            基本上,如果 Elvis 的左侧由于某种原因返回 null,则改为返回右侧。

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

            所以,如果数字不为空,它将打印数字,否则将打印“数字为空”。

            【讨论】:

              【解决方案8】:

              不过是一点点补充

              X = A ?: B
              

              如果AB 的计算结果都为nullX 仍将是null

              因此,如果您希望 X 始终为 non-null,请确保 B 始终为 non-null,或者如果 B 是函数或表达式,则始终计算为 non-null

              【讨论】:

                【解决方案9】:

                考虑下面的例子,

                var myStr:String? = null
                
                //trying to find out length of myStr, but it could be null, so a null check can be put as,
                
                val len = if (myStr != null){
                    myStr.length
                }
                else{
                    -1
                }
                

                使用elvis操作符,上面的代码可以写成一行

                val len = myStr?.length ?: -1     // will return -1 if myStr is null else will return length
                

                【讨论】:

                  【解决方案10】:

                  除了已经满足的内容之外,还有一种对我来说并不明显但很常见的好模式,例如您正在编写一个长函数,但如果某些内容为 null,则继续没有意义,您唯一能做的就是从该函数返回。通常你会写

                  something = expression
                  if (something == null) {
                         return
                  }
                  

                  有了猫王,它变得更短更优雅:

                  something = expression ?: return
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2018-05-12
                    • 1970-01-01
                    • 2012-05-30
                    • 2022-10-07
                    • 2018-07-18
                    • 1970-01-01
                    • 2014-06-24
                    相关资源
                    最近更新 更多