微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Scala 2.10 TypeTag的用法

我正在挖掘新的 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)

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

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

val tFilter = new TFilter[Foo]
messages collect tFilter.f[Foo]

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

res1: Seq[Foo] = List(1,hello,Foo(1))

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

PS0.试用了Scala 2.10.0-RC1和2.10.0-RC2

PS1.解决方法是用Manifest替换TypeTag,所以使用以下代码收集序列将按预期返回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]
}

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

解决方法

所以我认为这里的关键问题是你需要匹配msg的类型,但它的编译时类型是Any(来自PartialFunction声明).实际上,您希望为List [Any]中的每个元素使用不同的TypeTag.但是由于它们都具有编译时类型为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,Foo(1),List(1),List("a"))
messages collect new TFilter[Foo].f // produces List(Foo(1))

作为Ajran points out,就像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)

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐