Ternary Operators in Scala

假如想象 提交于 2019-12-06 16:36:38
jwvh

This might be a bit confusing for a "newbie", but you could attach a ternary method to the Boolean class like so.

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

Usage:

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

You should not need to use a ternary operator in Scala. In Scala, if is an expression not a statement, you can say val x = if (b) 1 else 2.

The usage of var in your example also points to a problem, because you can usually avoid this when you use the if as an expression.

Let's try to break down the code to avoid the var, i.e. first remove all if statements that are not expressions with a corresponding else and always provide both values:

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
}

Now we can define the condition for which either of countA and countB is one:

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

and then:

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

I think the short answer is that in Scala there is no ?: ternary operator. Although you can imitate the syntax using implicits (see @jwvh's answer), I think it doesn't really simplify anything.

There are a couple of important properties of the conventional ?:

  1. it always has two branches
  2. following from the previous property, the ternary operator always returns a value (this is mostly the point of using ?:)

    val result: Int = if (true) 1 else 2
    // result is 1
    
  3. branches are evaluated lazily

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

As you see, in Scala if-else (with else) construction satisfies these properties. This is not the case for if-else construction in some other languages, like C or Java, because it doesn't return a value.

So the bottom line is that in Scala you don't need a ternary operator, because you can just use if-else.

UPDATE

As Alexey Romanov mentions in the comments, if statement without else actually satisfies the first condition as well. When you write

val result = if (true) 1

it actually means if (true) 1 else (), so result will have type AnyVal instead of Int, because the return type of the if expression is the lowest common bound of the both branches (Int and Unit in this case).

Thilo

To expand on @0__'s answer (if that is his/her real name), you can also use tuples to assign to two variables at once.

val (countA, countB) = 
  if (validItem) {
    if (region.equalsIgnoreCase("US")) {
      if (itemList > 0) (0,1) else (1,0)
    } else {
      (0,1)
    }
  } else {
    (1,0)
  }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!