Scala 中的三元条件运算符

问题描述 投票:0回答:5

我想简化一下:

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

scala if-statement conditional-operator
5个回答
21
投票

您不需要在 Scala 中使用三元运算符。在 Scala 中,

if
是一个表达式而不是一个语句,你可以说
val x = if (b) 1 else 2

在您的示例中使用

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

让我们尝试分解代码以避免

var
,即首先删除所有不是具有相应
if
的表达式的
else
语句,并始终提供两个值:

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
}

现在我们可以定义

countA
countB
之一为 1 的条件:

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

12
投票

我认为简短的答案是,在 Scala 中存在 no

?:
三元条件运算符。尽管您可以使用隐式来模仿语法(请参阅@jwvh的answer),但我认为它并没有真正简化任何事情。

传统的技术有几个重要的特性

?:

  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
)构造满足这些属性。对于其他一些语言(如 C 或 Java)中的
if-else
构造来说,情况并非如此,因为它不返回值。

所以最重要的是,在

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

注:

正如 Alexey Romanov 在评论中提到的那样,没有

if
else
语句实际上也满足了第一个条件。当你写的时候

val result = if (true) 1

它实际上意味着

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


6
投票

这对于“新手”来说可能有点令人困惑,但是您可以像这样将三元方法附加到

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

3
投票

为了扩展@0__的答案(如果这是他/她的真名),您还可以使用元组一次分配给两个变量。

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

3
投票

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

val (countA, countB) =
  (validItem, region.equalsIgnoreCase("US"), itemList > 0) match {
    case (true, true, false) | (false, _, _) => (1, 0)
    case _                                   => (0, 1)
  }
© www.soinside.com 2019 - 2024. All rights reserved.