在回答我的问题How to develop macro to short-circuit null?时,有人向我指出了一个有很多答案的早期长线程,其中最引人注目的是https://stackoverflow.com/a/5569905。但它并不适用于像Int:
这样的Scala AnyVal“原语”object TestOp {
class SafeDereference[A](obj: A) {
def ?[B >: Null](function: A => B): B = if (obj == null) null else function(obj)
}
implicit def safeDereference[A](obj: A) = new SafeDereference(obj)
class C {
def getValue: Int = 0
}
def main(args: Array[String]) {
val c = new C
val x:Int = c ? (_.getValue)
}
}
给出了编译错误:
[error] TestOp.scala:14: type mismatch;
[error] found : Any
[error] required: Int
[error] val x:Int = c ? (_.getValue)
[error] ^
[error] one error found
[error] {file:/home/mmalak/streaming-demo/}default-ae36bd/compile:compile: Compilation failed
解决方法是将val x:Int替换为val x:java.lang.Integer,然后编译。有没有办法改进上面的SafeDereference,以便允许val x:Int?
其他信息
以下产生所需的输出。现在的问题是如何将类型转换为SafeDereference,以及如何处理所有其他Scala“基元”(布尔等)。
object TestOp {
class SafeDereference[A](obj: A) {
def ?[B >: Null](function: A => B): B = if (obj == null) null else function(obj)
}
implicit def safeDereference[A](obj: A) = new SafeDereference(obj)
class C {
def getValue: Int = 0
}
def main(args: Array[String]) {
val c:C = null
val x = (c ? (_.getValue)).asInstanceOf[java.lang.Integer].asInstanceOf[Int]
println("x="+x)
}
}
根据需要输出:
x=0
答案 0 :(得分:2)
你可以这样做。 Zero
特征允许您确定任何不是nullable
的对象的零值。在这种情况下,我为Numeric
类型添加了一个:
object TestOp {
trait Zero[T] {
def apply(): T
}
object Zero {
implicit def zeroNull[B >: Null] =
new Zero[B] { def apply = null }
implicit def zeroNumeric[B: Numeric] =
new Zero[B] { def apply = implicitly[Numeric[B]].zero }
}
implicit class SafeDereference[A](obj: A) {
def ?[B](function: A => B)(implicit zero: Zero[B]): B =
if (obj == null) zero() else function(obj)
}
class C {
def getValue: Int = 0
def getSomething: C = new C
}
def main(args: Array[String]) {
val c = new C
val x = c ? (_.getValue)
val y = c ? (_.getSomething)
}
}
对于Boolean
,您可以添加以下内容:
implicit def zeroBoolean[B >: Boolean] =
new Zero[B] { def apply = false }