Как написать правильный нуль-безопасный оператор объединения в 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