了解Scala AnyVal和Null

时间:2018-03-13 03:37:48

标签: scala

为什么以下编译?我知道AnyVal实例对应于底层主机系统中无法构造的东西,并且Null是所有引用类型的子类型,但不是值类型的子类型。我有一个我给safeMapDifferent的AnyVal类型的布尔值,但是不知道它如何满足U >: Null的约束。

object MyMainScala extends App {

  implicit class RichObject[T](o: T) {
    def safeMap[U](method: T => U)(implicit ev: Null <:< U): U =
      Option(o).flatMap(result => Option(method(result))).orNull

    def safeMapDifferent[U >: Null](method: T => U): U =
      Option(o).flatMap(result => Option(method(result))).orNull
  }

  override def main(args: Array[String]): Unit = {
    val testSubject = new Object() {
      def scalaBoolean: Boolean = ???
    }

    // println(testSubject.safeMap(_.scalaBoolean)) // If not commented, this will fail to compile as I expect.
    println(testSubject.safeMapDifferent(_.scalaBoolean).getClass) // Why does it compile?
  }
}

1 个答案:

答案 0 :(得分:5)

因为 Autoboxing 。如果您在predef.scala中看到,您会看到一堆将scala AnyVal转换为Java的隐式转化方法。

 /** @group conversions-anyval-to-java */
  implicit def boolean2Boolean(x: Boolean): java.lang.Boolean = x.asInstanceOf[java.lang.Boolean]

当您调用打印方法println(testSubject.safeMapDifferent(_.scalaBoolean).getClass)时,您提供T => U_.scalaBoolean,其中testSubject作为满足T type参数的参数并返回Boolean不满足U >: Null。收到此错误后,编译器会查找implicit methods而不是抛出异常,它会将Boolean转换为预期的U >: Null类型,并在boolean2Boolean中找到predef.scala满足此约束,因为java.land.Booleanreference类型。因此,编译正确执行代码。

def foo[U >: Null](o : U) = println(o)

foo(true) // compile correctly.
foo[java.lang.Boolean](true) //compile correctly, because true is implicitly converted to java Boolean and java.lang.Boolean is reference type and superType of scala.Null.

要避免这种情况,您必须静态提供类型参数:foo[Boolean](true) //won't compile.