Scala 2.10 TypeTag用法

4e6*_*4e6 10 reflection scala scala-2.10

我正在挖掘新的scala反射api,并且无法弄清楚为什么以下代码段不能按预期工作.给定层次结构(试图尽可能地简化):

import scala.reflect.runtime.universe._

trait TF[A] {
  implicit def t: TypeTag[A]

  def f[T <: A: TypeTag]: PartialFunction[Any, A] = {
    case msg: T if typeOf[T] =:= typeOf[A] => msg
  }
}

class TFilter[T: TypeTag] extends TF[T] {
  def t = typeTag[T]
}

case class Foo(x: Int)
Run Code Online (Sandbox Code Playgroud)

我希望方法f过滤给定类型的对象.所以下面的片段应该返回Seq[Foo]

val messages = Seq(1, "hello", Foo(1))

val tFilter = new TFilter[Foo]
messages collect tFilter.f[Foo]
Run Code Online (Sandbox Code Playgroud)

它实际上会返回,Seq[Foo]但其他消息未经过滤,这听起来像一个错误.

res1: Seq[Foo] = List(1, hello, Foo(1))
Run Code Online (Sandbox Code Playgroud)

问题.我使用TypeTag错误还是新反射api的缺陷?

PS0.试过Scala 2.10.0-RC12.10.0-RC2

PS1.解决方法是替换TypeTagManifest,因此collect序列上的以下代码List(Foo(1))将按预期返回.

trait MF[A] {
  implicit def m: Manifest[A]

  def f[T <: A: Manifest]: PartialFunction[Any, A] = {
    case msg: T if typeOf[T] =:= typeOf[A] => msg
  }
}

class MFilter[T: Manifest] extends MF[T] {
  def m = manifest[T]
}
Run Code Online (Sandbox Code Playgroud)

更新:与新Scala 2.10.0-RC2版本相同.

Ste*_*eve 6

所以我认为这里的关键问题是你需要匹配类型msg,但它的编译时类型是Any(来自PartialFunction声明).从本质上讲,你需要TypeTag为你的每个元素添加一个不同的元素List[Any].但是因为它们都具有编译时类型,Any因为所有这些都被放入同一个列表中,所以你不会得到一个TypeTag比这更具体的东西.

我想你可能想做的是用ClassTag而不是TypeTag:

trait TF[A] {
  implicit def t: ClassTag[A]

  def f: PartialFunction[Any, A] = {
    case msg: A => msg
  }
}

class TFilter[T: ClassTag] extends TF[T] {
  def t = classTag[T]
}

case class Foo(x: Int)

val messages = Seq(1, "hello", Foo(1), List(1), List("a"))
messages collect new TFilter[Foo].f // produces List(Foo(1))
Run Code Online (Sandbox Code Playgroud)

正如Ajran所指出的那样,就像Manifest版本一样,你必须要了解运行时类型的所有限制,包括擦除和装箱问题:

messages collect new TFilter[List[Int]].f // produces List(List(1), List("a"))
messages collect new TFilter[Int].f // produces List()
messages collect new TFilter[java.lang.Integer].f // produces List(1)
Run Code Online (Sandbox Code Playgroud)

关于如何使TypeTag模式匹配更有用的一些建议(例如SI-6517),但我认为只有当你用一个有用的对象匹配时才有用TypeTag,而不是一个编译时类型的对象Any.