为什么以下编译?我知道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?
}
}
答案 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.Boolean
是reference
类型。因此,编译正确执行代码。
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.