Scala 中的三元运算符

Ternary Operators in Scala

我想简化一下:

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 中使用三元运算符。

这对于 "newbie" 可能有点混乱,但您可以像这样将三元方法附加到 Boolean class。

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 = +

您应该不需要在 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

为了扩展(如果那是his/her真名),你也可以使用元组一次赋值给两个变量。

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

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

常规 ?:

有几个重要的属性
  1. 它总是有两个分支
  2. 从前面的 属性 开始,三元运算符总是 return 一个值 (这主要是使用 ?:)

    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,因为它没有 return 值。

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

更新

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

val result = if (true) 1

它实际上意味着 if (true) 1 else (),因此 result 将具有类型 AnyVal 而不是 Int,因为 if 的 return 类型] 表达式是两个分支的最低公共边界(在本例中为 IntUnit)。

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

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