k47.cz
mastodon twitter RSS
bandcamp explorer

Scala Elvis operator

25. 11. 2010 (před 12 lety) — k47 (CC by-sa)

Scala nemá Elvis operátor ?: jako Groovy, budoucí Java 8 nebo C#, protože se místo kontrol, jestli proměnná neobsahuje null, spoléhá na typ Option[T] a pattern matching. Avšak tento jazyk disponuje natolik flexibilní syntaxí, že není problém si podporu Elvis operátoru jednoduše dopsat.


Elvis operátor je vlastně jenom zkrácená verze ternárního operátoru. Takže x ?: "default" je stejné jako x != null ? x : "default".

Ve Scale se však nemůže jmenovat ?:, protože operátory, končící dvojtečkou, se ve volají v opačném pořadí. Tedy a ?: b by se vyhodnotilo jako b.?:(a) (resp. { val x = a; b.?:(x) } viz sekce 5.8 Programming in Scala).

// implementace
class Elvis[T](private val v: T) {
  def ?(arg: T): T = if (v == null) arg else v
}

implicit def convertToElvis[T](x: T) = new Elvis(x)

// test
var x: List[String] = List("a", "b", "c")
x ? List("Null")     // vrátí List(a, b, c)
x = null
x ? List("Null")     // vrátí List(Null)

Další věc, která je přítomná v Groovy a bude v Javě 8 je operátor ?., který slouží pro bezpečné volání metod objektu. Při použití operátoru ?. nikdy nevznikne výjimka NullPointerException, místo níž se vrátí null. Tedy x?.method() je stejné jako x != null ? x.method() : null.

A i tohle se dá ve Scale jednoduše implementovat. Pochopitelně není možné použít syntaxi x?.method(), místo toho se musíme spokojit s ?(x.method()).

// implementace

def ?[T](op: => T): T = try {
    op
  } catch {
    case e: NullPointerException => null.asInstanceOf[T]
  }

// test
class Test {
  def get = "test"
}

var t = new Test
?(t.get)             // všechno v pořádku, metoda vrátí "test"
t = null
?(t.get)             // nevyhodí `NullPointerException`, místo toho vrátí null
?(t.get) ?: "none"   // kombinace obojího
píše k47, ascii@k47.cz