模式匹配中的隐式ClassTag

时间:2016-04-26 20:07:07

标签: scala reflection

我们以此为例:

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标签的情况下进行模式匹配(在这种情况下我们无法区分擦除类型)?我的意思是,如果我声明一个隐式参数(由编译器自动提供),我是如何实现的,我得到一个行为,但如果我不这样做,我会得到不同的行为?

1 个答案:

答案 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)来将模式匹配中未经检查的类型测试转换为已检查的模式,其中ctClassTag[T]实例。在调用其他提取器之前必须进行类型测试。如果SomeExtractor(...)中的ct(SomeExtractor(...))无法检查,则T会变为SomeExtractor.unapply(x: T),但我们的实例为ClassTag[T]