【问题标题】:Ternary Operators in ScalaScala 中的三元运算符
【发布时间】:2017-03-31 08:13:07
【问题描述】:

我想简化一下:

var countA: Int = 0
var countB: Int = 0

if (validItem) {
  if (region.equalsIgnoreCase( "US" )) {
    if (itemList > 0) {
      countB = 1
    } else {
      countA = 1
    }
  } else {
    countB = 1
  }
} else {
  countA = 1
}

如何在 scala 中使用三元运算符。

【问题讨论】:

  • 这还能编译吗?一个if怎么会有三个else
  • 我认为这只是复制粘贴的混乱。可能 OP 是在问“如何在一个语句中写 if (itemList > 0) { countB = 1 } else { countA = 1 }?”。无论如何,这个问题的质量非常低,如果不改进,很可能会被关闭。
  • @Thilo 抱歉更新了。
  • @laughedelic 已更新。

标签: scala if-statement ternary-operator


【解决方案1】:

这是一个老问题,我正在解决当前的问题,所以我想我会留下一个基本的模式匹配解决方案。

val (countA, countB) =
  (validItem, region.equalsIgnoreCase("US"), itemList > 0) match {
    case (true, true, false) | (false, _, _) => (1, 0)
    case _                                   => (0, 1)
  }

【讨论】:

    【解决方案2】:

    我认为简短的回答是,在 Scala 中有 no ?: ternary operator。尽管您可以使用隐式来模仿语法(请参阅@jwvh 的答案),但我认为它并没有真正简化任何事情。

    传统的?:有几个重要的属性

    1. 它总是有两个分支
    2. 根据上一个属性,三元运算符总是返回一个值(这主要是使用?:的要点)

      val result: Int = if (true) 1 else 2
      // result is 1
      
    3. 分支被评估懒惰

      if (true) 1 else (0/0) // returns 1
      if (false) 0/0 else 2  // returns 2
      // i.e. 0/0 is not evaluated
      

    如您所见,在 Scala 中,if-else(带有else)构造满足这些属性。 if-else 在其他一些语言(如 C 或 Java)中的构造不是这种情况,因为它不返回值。

    所以底线是在Scala 中你不需要三元运算符,因为你可以只使用if-else

    更新

    正如 Alexey Romanov 在 cmets 中提到的那样,没有 elseif 语句实际上也满足第一个条件。当你写

    val result = if (true) 1
    

    它实际上表示if (true) 1 else (),因此result 将具有AnyVal 类型而不是Int,因为if 表达式的返回类型是两个分支的最低公共边界(IntUnit 在这种情况下)。

    【讨论】:

    • if without else 也满足这些属性:第二个分支是不可见的,但它存在并且具有 () 的值。
    • @AlexeyRomanov 谢谢,我完全忘记了if 的这个属性。我会将其添加到答案中,因为它可能会导致意外行为。
    【解决方案3】:

    这对于“新手”来说可能有点混乱,但您可以像这样将三元方法附加到 Boolean 类。

    implicit class Ternary[T](condition: Boolean) {
      def ??(a: => T, b: => T): T = if (condition) a else b
    }
    

    用法:

    (4 == 4)??("yes","no")         // res0: String = yes
    ("abc".length < 2).??(1,0)     // res1: Int = 0
    List('c').isEmpty.??('X','+')  // res2: Char = +
    

    【讨论】:

    • 这有助于定义 看起来像 三元运算符的东西,但我认为它并不能真正帮助简化 OP 示例中的代码。
    • @laughedelic,是的,我在 OP 有一个可编译的示例之前提出了这个问题。我认为标题是正确的,并且目标是三元运算符。我现在看到示例代码更复杂,但我的回答被接受了。去搞清楚。我认为OP在许多方面都感到困惑。我仍然不知道“1.5”应该是什么。
    • 对(我没有否决您的回答)。另一件事:在你的定义中?? 的参数应该是惰性的。
    • @laughedelic,同意。
    【解决方案4】:

    要扩展@0__'s answer(如果那是他/她的真名),您还可以使用元组一次分配给两个变量。

    val (countA, countB) = 
      if (validItem) {
        if (region.equalsIgnoreCase("US")) {
          if (itemList > 0) (0,1) else (1,0)
        } else {
          (0,1)
        }
      } else {
        (1,0)
      }
    

    【讨论】:

      【解决方案5】:

      您不需要在 Scala 中使用三元运算符。在 Scala 中,if 是表达式而不是语句,你可以说 val x = if (b) 1 else 2

      在您的示例中使用var 也指出了一个问题,因为当您使用if 作为表达式时,通常可以避免这种情况。

      让我们尝试分解代码以避免var,即首先删除所有不是具有相应else 的表达式的if 语句,并始终提供这两个值:

      var countA: Int = ???
      var countB: Int = ???
      
      if (validItem) {
        if (region.equalsIgnoreCase("US")) {
          if (itemList > 0) {
            countA = 0
            countB = 1
          } else {
            countA = 1
            countB = 0
          }
        } else {
          countA = 0
          countB = 1
        }
      } else {
        countA = 1
        countB = 0
      }
      

      现在我们可以定义countAcountB 中的任何一个为一的条件:

      val isUS     = region.equalsIgnoreCase("US")
      val hasItems = itemList > 0
      val isA      = !validItem || (isUS && !hasItems)
      val isB      = !isA
      // or: val isB = validItem && (!isUS || hasItems)
      

      然后:

      val countA   = if (isA) 1 else 0
      val countB   = if (isB) 1 else 0
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-10-06
        • 2017-07-02
        • 2021-08-01
        • 2018-09-10
        相关资源
        最近更新 更多