为什么Scala PartialFunction是DefinedAt方法总是返回true



我的代码如下。

case class C[T]() {
val pf:PartialFunction[Any,Any] = {
case i:T => i
}
}
println(C[Int]().pf.isDefinedAt(-1.0))

这打印CCD_ 1。为什么会发生这种情况?

由于类型擦除,您的代码基本上等于:

case class C[T]() {
val pf:PartialFunction[Any,Any] = {
case i:Any => i // this matches everything
}
}

您可以使用TypeTag来修复它:

import scala.reflect.runtime.universe._
case class C[T: TypeTag]() {
def pf[U: TypeTag]: PartialFunction[U, Any] = {
case i if typeOf[U] <:< typeOf[T] => i
}
}

使用中:

@ C[Int]().pf.isDefinedAt("")
res41: Boolean = false
@ C[Int]().pf.isDefinedAt(34)
res42: Boolean = true

这些实际上等于

@ C[Int]().pf[String].isDefinedAt("")
res41: Boolean = false
@ C[Int]().pf[Int].isDefinedAt(34)
res42: Boolean = true

其中类型U是推断的-它有一个限制,即当需要TypeTag时,它只能像编译器关于类型的知识一样精确。

您也可以尝试使用ClassTag[T]来使用运行时反射。。。但对于基元来说,它将失败

case class C[T]()(implicit classTag: scala.reflect.ClassTag[T]) {
def pf[U: TypeTag]: PartialFunction[U, Any] = {
case i if classTag.runtimeClass.isInstance(i) => i
}
}

导致

@ C[Int]().pf.isDefinedAt(34)
res2: Boolean = false
@ C[Int]().pf.isDefinedAt("")
res3: Boolean = false

问题是classTag将解析为Scala的int,而运行时将显示java.lang.Int:

@ case class C[T]()(implicit classTag: scala.reflect.ClassTag[T]) {
def pf: PartialFunction[Any, Any] = {
case i => println(s"T = ${classTag.runtimeClass.getName}, here: ${i.getClass.getName}")
}
}
defined class C
@ C[Int]().pf.isDefinedAt(34)
res7: Boolean = true
@ C[Int]().pf(34)
T = int, here: java.lang.Integer
res8: Any = ()

一般来说,这里没有完美的解决方案,你可以在这里和这里阅读更多关于类似问题的信息。

相关内容

  • 没有找到相关文章

最新更新