看到像this one之类的问题的答案涉及恐怖表演,比如试图抓住NPE并将错位的名称从堆栈轨迹中挖出来,我问这个问题所以我可以回答它。
欢迎评论或进一步改进。
答案 0 :(得分:36)
像这样:
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
答案 1 :(得分:0)
添加了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
更多例子
case class Obj[T](field: T)
test("last null") {
val obj: Obj[Obj[Obj[Obj[String]]]] = Obj(Obj(Obj(Obj(null))))
val res0 = CoalesceNull(obj)(_.field)(_.field)(_.field)(_.field)()
res0 should === (null)
val res1 = CoalesceNull(obj)(_.field)(_.field)(_.field)(_.field).orElse("not found")
res1 should === ("not found")
}
test("first null") {
val obj: Obj[Obj[Obj[Obj[String]]]] = null
val res0 = CoalesceNull(obj)(_.field)(_.field)(_.field)(_.field)()
res0 should === (null)
val res1 = CoalesceNull(obj)(_.field)(_.field)(_.field)(_.field).orElse("not found")
res1 should === ("not found")
}
test("middle null") {
val obj: Obj[Obj[Obj[Obj[String]]]] = Obj(Obj(null))
val res0 = CoalesceNull(obj)(_.field)(_.field)(_.field)(_.field)()
res0 should === (null)
val res1 = CoalesceNull(obj)(_.field)(_.field)(_.field)(_.field).orElse("not found")
res1 should === ("not found")
}
test("not null") {
val obj: Obj[Obj[Obj[Obj[String]]]] = Obj(Obj(Obj(Obj("something"))))
val res0 = CoalesceNull(obj)(_.field)(_.field)(_.field)(_.field)()
res0 should === ("something")
val res1 = CoalesceNull(obj)(_.field)(_.field)(_.field)(_.field).orElse("not found")
res1 should === ("something")
}
}