带有TypeTag的泛型类型上的Scala模式匹配会生成警告,而ClassTag不会吗? [英] Scala pattern matching on generic type with TypeTag generates a warning while ClassTag not?
问题描述
我有两种非常相似的方法。唯一的区别是使用 ClassTag
和 TypeTag
:
< pre class = lang-scala prettyprint-override>
def matchClass [A:ClassTag](v:Any)=
v match {
case a:A => 是A
情况_ => not A
}
def matchType [A:TypeTag](v:Any)= ... //与matchClass
相同的代码 matchType
会显示编译警告,但 matchClass不会显示/ code>:
抽象类型模式A是未选中的,因为通过擦除情况a消除了它:A
为什么会有警告?为什么只显示 TypeTag
而不显示 ClassTag
?
您不会看到 classTag
的警告,因为该检查仅适用于以下情况:
scala> matchClass [Int]( aaa)
res82:字符串=不是A
scala> matchClass [Int](5)
res83:字符串=它是A
为 typeTag
工作:
scala> matchType [Int](5)
res84:字符串=它是A
scala> matchType [Int]( aaa)
res85:字符串=它是A
原因就是为了在classTags上进行模式匹配(当看到隐式)时,编译器生成如下内容:
case a:一个if classTag [ A] .runtimeClass.isInstance(a)=> ...
无法获取 runtimeClass
通常用于 TypeTag
(考虑编译和运行时,请参见UPDATE以了解仅允许在运行时中提取它的特定情况),因此这就是为什么编译器不会改变他们。默认情况下,由于擦除,模式匹配无法与通用(多态)类型匹配,因此默认情况下您会看到该警告:
scala> def matchGeneric [A](v:任何)=
| v match {
|情况a:A => 是A
|情况_ => 不是A
| }
< console>:28:警告:由于取消了
的情况a:A => 是A
^
matchGeneric:[A](v:任何)字符串
更新:如@Seth Tisue所述,标签来自运行时Universe(仅) 您可以为其获得运行时类(但您必须先创建一个镜像)。
参考:
编译器通过包装
(_:T)
类型尝试将模式匹配中的未检查类型测试转换为已检查类型模式为ct(_:T)
,其中ct
是ClassTag [T]
实例。在调用其他提取器之前,必须进行必要的类型测试。如果SomeExtractor(...)
会变成ct(SomeExtractor(...))
SomeExtractor.unapply(x:T)
中的> T 是不可检查的,但是我们有一个ClassTag [T]的实例
。
TypeTag
scaladocs和语言规范本身不要提及 TypeTags
任何这样的功能
无法确定为什么某些功能未实现,因此任何猜测都会被认为是(并且超出了SO范围,并且是甚至与您的问题直接相关,但要回答@Tom的评论)。不过(从2.12版本开始)...
这可能是因为 ClassTag仅提供对类型的运行时类的访问,并且是< a href = http://www.scala-lang.org/api/2.12.6/ rel = nofollow noreferrer> scala库(即使其软件包为 scala .reflect。
),而TypeTags是单独的(且相当广泛)反射API的一部分,因此根据 universe来引用编译或运行时
它们在里面,因此(在合成过程中!)为这些写额外的支票不仅会使(对用户)造成混淆,而且对语言开发人员也将造成困难:综合本身处于不同的状态(编译器)模块,并且[synthesis]不依赖在反射上(仅限scala库)进行模式匹配综合在早期的 patmat阶段。另外,scala spec(12.3.4.2 Variance)提到了使用ClassTag进行数组实例化的综合调整,这(非常有推测性)可能意味着ClassTag与语法糖功能更加集成。
I have two very similar methods. The only difference is the use of ClassTag
and TypeTag
:
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
A compile warning will show for matchType
, but not for matchClass
:
abstract type pattern A is unchecked since it is eliminated by erasure case a: A
Why is there a warning? why does it show only for TypeTag
and not ClassTag
?
You don't see a warning for classTag
because that check simply works for those:
scala> matchClass[Int]("aaa")
res82: String = not A
scala> matchClass[Int](5)
res83: String = it's A
And doesn't work for typeTag
:
scala> matchType[Int](5)
res84: String = it's A
scala> matchType[Int]("aaa")
res85: String = it's A
The reason is that for pattern matching on classTags (when it's seeing an implicit) compiler generates something like:
case a: A if classTag[A].runtimeClass.isInstance(a) => ...
There is no way to get runtimeClass
for TypeTag
s in general (considering both compile&runtime, see the UPDATE for a specific case allowing to extract it in runtime only), so that's why compiler doesn’t transform them. By default, pattern matching can't match on generic (polymorphic) types because of erasure, so you can see that warning by default:
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
UPDATE: As @Seth Tisue mentioned when a tag comes from run-time universe (only) you can get a runtime class for it (but you gonna have to create a mirror first).
Reference:
As per scaladocs of ClassTag
itself:
The compiler tries to turn unchecked type tests in pattern matches into checked ones by wrapping a
(_: T)
type pattern asct(_: T)
, wherect
is theClassTag[T]
instance. Type tests necessary before calling other extractors are treated similarly.SomeExtractor(...)
is turned intoct(SomeExtractor(...))
ifT
inSomeExtractor.unapply(x: T)
is uncheckable, but we have an instance ofClassTag[T]
.
TypeTag
scaladocs and language spec itself don't mention any such functionality for TypeTags
Speculative explanation
There is no way to know for certain why some features are implemented or not, so any speculation would be opinionated (and out of SO scope, and isn't even related to your question directly, but to answer @Tom's comment). Nevertheless (as of 2.12)...
This is probably because "ClassTags provide access only to the runtime class of a type" and are part of scala-library (even though their package is scala.reflect.
), while TypeTags are a part of a separate (and quite wide-broad) reflection API thus are meant to refer to either compile or run time depending on the universe
they're in, so writing the additional checks (during synthesis!!) for those would be not just confusing (for users) but also hard for language developers: synthesis itself is in a different (compiler) module and [synthesis] doesn't depend on reflection (only scala-library) as pattern matching synthesis is happening on early "patmat" stage. Also, scala spec (12.3.4.2 Variance) mentions usage of ClassTag's for synthetic adjustments of array instantiations which (very speculatively) could mean that ClassTags are more integrated with the "syntax sugar"-features.
这篇关于带有TypeTag的泛型类型上的Scala模式匹配会生成警告,而ClassTag不会吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!