带有TypeTag的泛型类型上的Scala模式匹配会生成警告,而ClassTag不会吗? [英] Scala pattern matching on generic type with TypeTag generates a warning while ClassTag not?

查看:86
本文介绍了带有TypeTag的泛型类型上的Scala模式匹配会生成警告,而ClassTag不会吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两种非常相似的方法。唯一的区别是使用 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(仅) 您可以为其获得运行时类(但您必须先创建一个镜像)。






参考:



按照 ClassTag 本身的scaladocs


编译器通过包装(_: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 TypeTags 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 as ct(_: T), where ct is the ClassTag[T] instance. Type tests necessary before calling other extractors are treated similarly. SomeExtractor(...) is turned into ct(SomeExtractor(...)) if T in SomeExtractor.unapply(x: T) is uncheckable, but we have an instance of ClassTag[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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆