改进Scala中的Groovy安全解除引用运算符

时间:2013-04-11 21:43:48

标签: scala operator-overloading dereference

在回答我的问题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

1 个答案:

答案 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 }