Scala 2.10 TypeTag 用法 [英] Scala 2.10 TypeTag usage

查看:48
本文介绍了Scala 2.10 TypeTag 用法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究新的 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-RC12.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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆