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
调用函数
if
t=:=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))