我偶然发现了一种奇怪的情况,即导入 reflect.runtime.universe._
会导致 reflect.runtime.universe.RuntimeClass
被推断为 Nothing
似乎更合适。
考虑这个简单的方法和 List
:
import scala.reflect.ClassTag
def find[A : ClassTag](l: List[Any]): Option[A] =
l collectFirst { case a: A => a }
val list = List(1, "a", false)
我可以使用它来查找某种类型的
List
中的第一个元素,并且按预期运行良好。scala> find[String](list)
res1: Option[String] = Some(a)
scala> find[Long](list)
res2: Option[Long] = None
如果我不提供类型参数,那么
A
被推断为 Nothing
,所以我得到 Option[Nothing]
,也符合预期。scala> find(list)
res3: Option[Nothing] = None
但是,如果我
import scala.reflect.runtime.universe._
并且再次不提供类型参数, A
现在被推断为 reflect.runtime.universe.RuntimeClass
而不是 Nothing
。scala> find(list)
res4: Option[reflect.runtime.universe.RuntimeClass] = None
^ What?
这不是一个大问题,因为如果不手动提供类型参数,我很难想象
find
方法的很多用例,但为什么会发生这种情况? ClassTag
似乎是部分原因,因为再次删除它会导致 Nothing
被推断(尽管由于擦除而完全破坏了该方法)。这里发生了什么? 最佳答案
这看起来像是内部设计运行时 Universe
的一些完全意想不到的副作用。scala.reflect.runtime.universe
的类型为 scala.reflect.api.JavaUniverse
。
通过导入它的所有成员,您可以导入 - 特别是 - 一组由 Universe 扩展的 ClassTag
trait 中定义的隐式 scala.reflect.api.ImplicitTags
值。ImplicitTags
trait 引入了大约 90 个不同的隐式 ClassTag
值。其中,有这样一个:
implicit val RuntimeClassTag: ClassTag[RuntimeClass]
看起来编译器比其他人更喜欢它,因为它决定在推断任意
ClassTag[A]
时使用它。这是为什么?这是因为 RuntimeClassTag
在 scala.reflect.api.JavaUniverse
中被覆盖,并且子类中定义的隐式值优先于父类(super class)中定义的隐式值(如重载解析规则中的某处指定 - SLS 6.26.3)因此,总而言之,编译器为
RuntimeClass
推断 A
与 ClassTag
上下文绑定(bind),因为它在范围内看到了这个东西(由 Universe 上的通配符导入引入):trait JavaUniverse extends Universe { self =>
type RuntimeClass = java.lang.Class[_]
implicit val RuntimeClassTag: ClassTag[RuntimeClass] =
ClassTag[RuntimeClass](classOf[RuntimeClass])
...
}
关于scala - 当reflect.runtime.universe._存在时,为什么reflect.runtime.universe.RuntimeClass被推断为Nothing?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30147880/