Scala 2.10 TypeTag 用法 [英] Scala 2.10 TypeTag usage
问题描述
我正在研究新的 Scala 反射 api,但无法弄清楚为什么以下代码段没有按预期工作.给定层次结构(尽量简化):
I'm digging new scala reflection api and can't figure out why the following snippet doesn't work as expected. Given hierarchy (tried to simplify as much as I can):
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)
我希望方法 f
过滤给定类型的对象.所以下面的代码片段应该返回 Seq[Foo]
I expect method f
to filter objects of given type. So the following snippet should return Seq[Foo]
val messages = Seq(1, "hello", Foo(1))
val tFilter = new TFilter[Foo]
messages collect tFilter.f[Foo]
它实际上返回了 Seq[Foo]
但其他消息未过滤,这听起来像是一个错误.
And it actually returns Seq[Foo]
but with other messages unfiltered, which sounds like a bug.
res1: Seq[Foo] = List(1, hello, Foo(1))
问题.是我使用了TypeTag
错误还是新反射api 的缺陷?
Question. Am I using TypeTag
wrong or it is defect of new reflection api?
PS0.尝试使用 Scala 2.10.0-RC1
和 2.10.0-RC2
PS1.解决方法是将 TypeTag
替换为 Manifest
,因此使用以下代码 collect
on sequence 将返回 List(Foo(1))
符合预期.
PS1. The workaround is to replace TypeTag
with Manifest
, so with the following code collect
on sequence will return List(Foo(1))
as expected.
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]
}
更新:与新的 Scala 2.10.0-RC2
版本相同.
Update: Same with new Scala 2.10.0-RC2
release.
推荐答案
所以我认为这里的关键问题是你需要匹配 msg
的类型,但是它的编译时类型是Any
(来自 PartialFunction
声明).本质上,您需要为 List[Any]
中的每个元素使用不同的 TypeTag
.但是由于它们都具有 Any
的编译时类型,因为所有这些都被放入同一个列表中,所以您不会得到比以下更具体的 TypeTag
So I think the key problem here is that you need to match against the type of msg
, but its compile-time type is Any
(from the PartialFunction
declaration). Essentially, you want a different TypeTag
for each element in your List[Any]
. But since they all have compile-time type of Any
by virtue of all being put into the same list, you're not going to get a TypeTag
that's any more specific than that.
我认为您可能想要做的是使用 ClassTag
而不是 TypeTag
:
I think what you probably want to do is use ClassTag
instead of 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))
正如 Ajran 指出的,就像 Manifest
版本一样,您必须请注意运行时类型的所有限制,包括擦除和装箱问题:
As Ajran points out, just like the Manifest
version, you'll have to be aware of all the limitations of runtime types including erasure and boxing issues:
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)
有一些关于如何使 TypeTag
对模式匹配更有用的建议(例如 SI-6517),但我认为这些只会在您匹配具有有用 TypeTag
的对象而不是具有编译时类型的对象时有所帮助Any
.
There are some suggestions about how to make TypeTag
more useful for pattern matching (e.g. SI-6517), but I think those will only help when you're matching against an object with an useful TypeTag
, not an object with compile-time type of Any
.
这篇关于Scala 2.10 TypeTag 用法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!