我们以此为例:
import scala.reflect._
def get[T](list: List[Any])(implicit tag: ClassTag[T]) = {
list.flatMap {
case element: T => Some(element)
case _ => None
}
}
我可以使用get()
从列表中获取T
类型的值(例如get[String](list)
将为我提供该列表中的所有字符串)。
现在,我了解编译器会自动提供类型ClassTag[String]
的值。我也明白ClassTag
是一个类型类,在幕后的某处,有一段代码表示implicitly[ClassTag[T]].getRuntimeClass()
或其他什么。
但如果是这样的话,为什么我们可以在没有class标签的情况下进行模式匹配(在这种情况下我们无法区分擦除类型)?我的意思是,如果我声明一个隐式参数(由编译器自动提供),我是如何实现的,我得到一个行为,但如果我不这样做,我会得到不同的行为?
答案 0 :(得分:5)
编译器会自动将您的代码粗略地翻译为:
def get[T](list: List[Any])(implicit tag: ClassTag[T]) = list.flatMap {
case (element @ tag(_: T)) => Some(element)
case _ => None
}
ClassTag
有一个unapply(x: Any)
重载,允许它对值进行模式匹配。我已清理从reify
获取的树只显示相关部分,但这将显示完整的树:
scala.reflect.runtime.universe.reify {
def get[T](list: List[Any])(implicit tag: ClassTag[T]) = {
list.flatMap {
case element: T => Some(element)
case _ => None
}
}
}
另见scaladoc:
编译器尝试通过将
(_: T)
类型模式包装为ct(_: T)
来将模式匹配中未经检查的类型测试转换为已检查的模式,其中ct
是ClassTag[T]
实例。在调用其他提取器之前必须进行类型测试。如果SomeExtractor(...)
中的ct(SomeExtractor(...))
无法检查,则T
会变为SomeExtractor.unapply(x: T)
,但我们的实例为ClassTag[T]
。