Как написать правильный нуль-безопасный оператор объединения в scala?

Увидев ответы на такие вопросы, как этот с участием ужасов, таких как попытка поймать NPE и вытащить искалеченное имя из трассировки стека, я задаю этот вопрос, чтобы ответить на него.

Комментарии или дальнейшие улучшения приветствуются.

2 ответа

Вот так:

case class ?:[T](x: T) {
  def apply(): T = x
  def apply[U >: Null](f: T => U): ?:[U] =
    if (x == null) ?:[U](null)
    else ?:[U](f(x))
}

И в действии:

scala> val x = ?:("hel")(_ + "lo ")(_ * 2)(_ + "world")()
x: java.lang.String = hello hello world

scala> val x = ?:("hel")(_ + "lo ")(_ => (null: String))(_ + "world")()
x: java.lang.String = null

Добавлен orElse

      case class ?:[T](x: T) {
  def apply(): T = x
  def apply[U >: Null](f: T => U): ?:[U] =
    if (x == null) ?:[U](null)
    else ?:[U](f(x))
  def orElse(y: T): T = 
    if (x == null) y
    else x
}
      scala> val x = ?:(obj)(_.subField)(_.subSubField).orElse("not found")
x: java.lang.String = not found

Или, если вы предпочитаете именованный синтаксис, а не синтаксис оператора

      case class CoalesceNull[T](x: T) {
  def apply(): T = x
  def apply[U >: Null](f: T => U): CoalesceNull[U] =
    if (x == null) CoalesceNull[U](null)
    else CoalesceNull[U](f(x))
  def orElse(y: T): T =
    if (x == null) y
    else x
}
      scala> val x = CoalesceNull(obj)(_.subField)(_.subSubField).orElse("not found")
x: java.lang.String = not found
Другие вопросы по тегам