使用TypeTag的泛型类型上的Scala模式匹配会产生警告而ClassTag不会生成警告吗?

时间:2015-12-28 14:52:49

标签: scala reflection compiler-warnings

我有两个非常相似的方法。唯一的区别是使用ClassTagTypeTag

def matchClass[A: ClassTag](v: Any) =
    v match {
        case a: A => "it's A"
        case _ => "not A"
    }

def matchType[A: TypeTag](v: Any) = ... // same code as matchClass

matchType会显示编译警告,但matchClass不显示编译警告:
abstract type pattern A is unchecked since it is eliminated by erasure case a: A

为什么会有警告?为什么它只显示TypeTag而不显示ClassTag

1 个答案:

答案 0 :(得分:8)

您没有看到classTag的警告,因为该检查只适用于那些:

scala> matchClass[Int]("aaa")
res82: String = not A

scala> matchClass[Int](5)
res83: String = it's A 

并不适用于typeTag

scala> matchType[Int](5)
res84: String = it's A

scala> matchType[Int]("aaa")
res85: String = it's A

原因是对于classTags上的模式匹配(当它看到一个隐式时)编译器生成如下内容:

case a: A if classTag[A].runtimeClass.isInstance(a) => ...

一般来说,runtimeClass无法获得TypeTag(考虑编译和运行时,请参阅UPDATE以了解允许仅在运行时提取它的特定情况),这就是编译器的原因不改变它们。默认情况下,由于擦除,模式匹配在泛型(多态)类型上无法匹配,因此默认情况下您可以看到该警告:

 scala> def matchGeneric[A](v: Any) =
 |     v match {
 |         case a: A => "it's A"
 |         case _ => "not A"
 |     }
<console>:28: warning: abstract type pattern A is unchecked since it is eliminated by erasure
               case a: A => "it's A"
                       ^
matchGeneric: [A](v: Any)String

更新:正如@Seth Tisue提到when a tag comes from run-time universe (only)你可以为它获得一个运行时类(但你必须先创建一个镜像)。

参考:

根据ClassTag本身的scaladocs

  

编译器尝试通过将(_: T)类型模式包装为ct(_: T)来将模式匹配中未经检查的类型测试转换为已检查的模式,其中ctClassTag[T]实例。在调用其他提取器之前必须进行类型测试。如果SomeExtractor(...)中的ct(SomeExtractor(...))无法检查,则T会变为SomeExtractor.unapply(x: T),但我们的实例为ClassTag[T]

TypeTag scaladocs和语言规范本身并未提及TypeTags

的任何此类功能

推测性解释

没有办法确定某些功能是否实现的原因,因此任何推测都是固执的(并且超出SO范围,甚至不直接与您的问题相关,而是回答@汤姆的评论)。尽管如此(截至2.12)......

这可能是因为“ClassTags仅提供对类型的运行时类的访问”并且是scala-library的一部分(即使它们的包是scala.reflect.),而TypeTags是单独的一部分(并且相当广泛)反射API因此意味着根据它们所在的universe来指代编译或运行时间,因此为那些编写额外的检查(在合成期间!!)不仅仅是混淆(对于用户)但对语言开发人员来说也很难:合成本身在不同的(compiler)模块中,[综合]不依赖于reflection(只有scala-library)作为模式匹配合成正在早期的“patmat”舞台上发生。此外,scala spec(12.3.4.2 Variance)提到了ClassTag的使用,用于数组实例的合成调整(非常推测性地)可能意味着ClassTag与“syntax sugar”特征更加集成。