Scala 如果与ClassTag一起使用,则模式匹配会选择错误的大小写
差异和Scala 如果与ClassTag一起使用,则模式匹配会选择错误的大小写,scala,reflection,covariance,Scala,Reflection,Covariance,差异和类标签或类型标签之间有什么联系 我有两种类型T1和T2,它们用作类型参数 case class T1() case class T2() 我有一个抽象类,带有一个不变的类型参数和一个子类,如果我想检查类型参数的类型,它只在模式中没有类型检查的情况下工作,只是在保护中。如果存在型式试验,则始终选择第一种情况 类型检查是必要的,因为在我的实际代码中,我希望为每种类型调用不同的函数。[T1]中的和[T2]中的有单独的功能 abstract class In[T] case class VIn[
类标签
或类型标签
之间有什么联系
我有两种类型T1
和T2
,它们用作类型参数
case class T1()
case class T2()
我有一个抽象类,带有一个不变的类型参数和一个子类,如果我想检查类型参数的类型,它只在模式中没有类型检查的情况下工作,只是在保护中。如果存在型式试验,则始终选择第一种情况
类型检查是必要的,因为在我的实际代码中,我希望为每种类型调用不同的函数。[T1]中的和[T2]
中的有单独的功能
abstract class In[T]
case class VIn[T]() extends In[T]
def test1[T:ClassTag](v:In[T]) = v match {
case x : VIn[T1@unchecked] if classTag[T] == classTag[T1] => "T1"
case y : VIn[T2@unchecked] if classTag[T] == classTag[T2] => "T2"
}
test1(VIn[T1]()) //T1
test1(VIn[T2]()) //T1 !!!
def test2[T:ClassTag](v:In[T]) = v match {
case x if classTag[T] == classTag[T1] => "T1"
case y if classTag[T] == classTag[T2] => "T2"
}
test2(VIn[T1]()) //T1
test2(VIn[T2]()) //T2
在处理许多示例中使用的列表
类型时,我意识到,如果将类型参数更改为协变,它将在两个测试中都起作用
abstract class Co[+T]
case class VCo[T]() extends Co[T]
def test1[T:ClassTag](v:Co[T]) = v match {
case x : VCo[T1@unchecked] if classTag[T] == classTag[T1] => "T1"
case y : VCo[T2@unchecked] if classTag[T] == classTag[T2] => "T2"
}
test1(VCo[T1]()) // T1
test1(VCo[T2]()) // T2
def test2[T:ClassTag](v:Co[T]) = v match {
case x if classTag[T] == classTag[T1] => "T1"
case y if classTag[T] == classTag[T2] => "T2"
}
test2(VCo[T1]()) // T1
test2(VCo[T2]()) // T2
为什么不变量类型的第一次测试失败?没有编译器警告或运行时错误,它只是选择了第一种情况,但防护显然是错误的,如test2
中所示,我肯定认为这是一个编译器错误
def test1[T:ClassTag](v:In[T]) = {
val t1 = classTag[T] == classTag[T1]
val t2 = classTag[T] == classTag[T2]
println(v match {
case x : VIn[T1@unchecked] if t1 => "T1"
case y : VIn[T2@unchecked] if t2 => "T2"
})
v match {
case x:In[T1] if classTag[T] == classTag[T1] => "T1"
case y: In[T2] if classTag[T] == classTag[T2] => "T2"
}}
使用-Xprint:typer
打印显示(证据
):
模式匹配的if
语句为:
scala.reflect.`package`.classTag[T](evidence$1).==(scala.reflect.`package`.classTag[T1](evidence$1))
scala.reflect.`package`.classTag[T](evidence$1).==(scala.reflect.`package`.classTag[T2](evidence$1))
编译器正在将证据$1
传递给classTag[1]()
和classTag[2]()
的隐式参数。所以它实际上是在和自己比较。作为一种解决方法,如您所建议的test2
或预先计算的(如果似乎有效)。看起来像一个bug。没有编译器警告,因为您正在使用未选中的@
。但奇怪的是,在您的第一个示例中,classTag[T1]
在传递VIn[T2]
时实际上是classTag[T2]
,因此if
语句的结果为真。好像出于某种原因,T1
被视为T2
。也就是说,不管怎样,类型测试是没有结果的,你可以不用它。@m-z我需要类型测试,因为我不想用x
调用函数ift=:=T1
。类型测试使编译器相信x
属于VIn[T1]
类型,否则我会得到一个错误,VIn[T]
无法与VIn[T1]
匹配。我可以使用instanceOf
,但是让模式中的所有内容都匹配对我来说更好。case VIn[T1]
不是很有用,而是依赖于ClassTag
比较。如果(classTag[T]==classTag[T1])=>…
,您可以改为使用案例VIn[u],它仍然会检查VIn
,并且不会受到该错误的影响。
scala.reflect.`package`.classTag[T](evidence$1).==(scala.reflect.`package`.classTag[T1](evidence$1))
scala.reflect.`package`.classTag[T](evidence$1).==(scala.reflect.`package`.classTag[T2](evidence$1))