如果与 ClassTag 一起使用,模式匹配会选择错误的大小写
Pattern Matching chooses the wrong case if used with ClassTag
方差和ClassTags
或TypeTags
有什么关系?
我有两种类型 T1
和 T2
,用作类型参数。
case class T1()
case class T2()
我有一个带有不变类型参数和一个子class的抽象class,如果我想检查类型参数的类型,它只有在没有类型检查的情况下才有效格局,就在守卫之中。如果存在类型测试,它总是选择第一种情况。
类型检查是必要的,因为在我的真实代码中我想为每种类型调用不同的函数。 In[T1]
和 In[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
在尝试许多示例中使用的 List
类型时,我意识到如果将类型参数更改为协变,它在两个测试中都有效。
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
为什么 invarinat 类型的第一个测试失败了?没有编译器警告或运行时错误,它只是选择第一种情况,但警卫显然是错误的,如 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
打印显示 (evidence
):
def test1[T](v: In[T])(implicit evidence: scala.reflect.ClassTag[T]): String = {
....
val t1: Boolean = scala.reflect.`package`.classTag[T](evidence).==
(scala.reflect.`package`.classTag[T1]((ClassTag.apply[T1](classOf[T1]): scala.reflect.ClassTag[T1])))
val t2: Boolean = scala.reflect.`package`.classTag[T](evidence).==
(scala.reflect.`package`.classTag[T2]((ClassTag.apply[T2](classOf[T2]): scala.reflect.ClassTag[T2]))) //classTag[T] == classTag[T2]
模式匹配的if
语句为:
scala.reflect.`package`.classTag[T](evidence).==(scala.reflect.`package`.classTag[T1](evidence))
scala.reflect.`package`.classTag[T](evidence).==(scala.reflect.`package`.classTag[T2](evidence))
编译器正在将 evidence
传递给 classTag[1]()
和 classTag[2]()
的隐式参数。所以它实际上是在与自己进行比较。作为解决方法,正如您所建议的 test2
或预先计算的 if
似乎可行。
方差和ClassTags
或TypeTags
有什么关系?
我有两种类型 T1
和 T2
,用作类型参数。
case class T1()
case class T2()
我有一个带有不变类型参数和一个子class的抽象class,如果我想检查类型参数的类型,它只有在没有类型检查的情况下才有效格局,就在守卫之中。如果存在类型测试,它总是选择第一种情况。
类型检查是必要的,因为在我的真实代码中我想为每种类型调用不同的函数。 In[T1]
和 In[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
在尝试许多示例中使用的 List
类型时,我意识到如果将类型参数更改为协变,它在两个测试中都有效。
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
为什么 invarinat 类型的第一个测试失败了?没有编译器警告或运行时错误,它只是选择第一种情况,但警卫显然是错误的,如 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
打印显示 (evidence
):
def test1[T](v: In[T])(implicit evidence: scala.reflect.ClassTag[T]): String = {
....
val t1: Boolean = scala.reflect.`package`.classTag[T](evidence).==
(scala.reflect.`package`.classTag[T1]((ClassTag.apply[T1](classOf[T1]): scala.reflect.ClassTag[T1])))
val t2: Boolean = scala.reflect.`package`.classTag[T](evidence).==
(scala.reflect.`package`.classTag[T2]((ClassTag.apply[T2](classOf[T2]): scala.reflect.ClassTag[T2]))) //classTag[T] == classTag[T2]
模式匹配的if
语句为:
scala.reflect.`package`.classTag[T](evidence).==(scala.reflect.`package`.classTag[T1](evidence))
scala.reflect.`package`.classTag[T](evidence).==(scala.reflect.`package`.classTag[T2](evidence))
编译器正在将 evidence
传递给 classTag[1]()
和 classTag[2]()
的隐式参数。所以它实际上是在与自己进行比较。作为解决方法,正如您所建议的 test2
或预先计算的 if
似乎可行。