为了账号安全,请及时绑定邮箱和手机立即绑定

如何绕过Scala上的类型擦除?或者,为什么不能获得集合的类型参数?

如何绕过Scala上的类型擦除?或者,为什么不能获得集合的类型参数?

如何绕过Scala上的类型擦除?或者,为什么不能获得集合的类型参数?在Scala上,一个可悲的事实是,如果您实例化一个List[Int],您可以验证您的实例是一个列表,并且可以验证它的任何单个元素是否是Int,但不能验证它是否是List[Int],这一点很容易验证:scala> List(1,2,3) match {      | case l : List[String] => println("A list of strings?!")      | case _ => println("Ok")      | }warning: there were unchecked warnings; re-run with -unchecked for details A list of strings?!未选中的选项将指责直接归咎于类型擦除:scala>  List(1,2,3) match {      |  case l : List[String] => println("A list of strings?!")      |  case _ => println("Ok")      |  }<console>:6: warning: non variable type-argument String in type pattern is unchecked since it is eliminated by erasure              case l : List[String] => println("A list of strings?!")                  ^A list of strings?!为什么,我怎么才能避开它?
查看完整描述

3 回答

?
杨魅力

TA贡献1811条经验 获得超5个赞

这个答案使用Manifest-API,它在Scala2.10中被废弃。请参阅下面的答案,以获得更多最新解决方案。

Scala是使用TypeErasure定义的,因为Java虚拟机(JVM)与Java不同,没有泛型。这意味着,在运行时,只有类存在,而不是其类型参数。在本例中,JVM知道它正在处理scala.collection.immutable.List,但不是将此列表参数化为Int.

幸运的是,Scala中有一个特性可以让您绕过它。是因为舱单..Manifest是一个类,其实例是表示类型的对象。由于这些实例是对象,所以可以传递它们、存储它们,并通常对它们调用方法。在隐式参数的支持下,它成为一种非常强大的工具。例如,以下面的例子为例:

object Registry {
  import scala.reflect.Manifest

  private var map= Map.empty[Any,(Manifest[_], Any)] 

  def register[T](name: Any, item: T)(implicit m: Manifest[T]) {
    map = map.updated(name, m -> item)
  }

  def get[T](key:Any)(implicit m : Manifest[T]): Option[T] = {
    map get key flatMap {
      case (om, s) => if (om <:< m) Some(s.asInstanceOf[T]) else None
    }     
  }}scala> Registry.register("a", List(1,2,3))scala> Registry.get[List[Int]]("a")res6: Option[List[Int]] = Some(List(1, 2, 3))scala
  > Registry.get[List[String]]("a")res7: Option[List[String]] = None

在存储元素时,我们也会存储其中的“报表”。Manifest是一个类,其实例表示Scala类型。这些对象比JVM具有更多的信息,这使我们能够测试完整的参数化类型。

不过,请注意,aManifest仍然是一个不断发展的特征。作为其局限性的一个例子,它目前对方差一无所知,并且假设一切都是协变的。我希望一旦完成目前正在开发的Scala反射库,它将变得更加稳定和可靠。


查看完整回答
反对 回复 2019-06-06
?
白猪掌柜的

TA贡献1893条经验 获得超10个赞

您可以使用Typeable类型类无形为了得到你想要的结果,

REPL样本会话,

scala> import shapeless.syntax.typeable._import shapeless.syntax.typeable._

scala> val l1 : Any = List(1,2,3)l1: Any = List(1, 2, 3)scala> l1.cast[List[String]]res0: Option[List[String]] = Nonescala
> l1.cast[List[Int]]res1: Option[List[Int]] = Some(List(1, 2, 3))

这个cast在此范围内,操作将尽可能精确地擦除wrt。Typeable实例可用。


查看完整回答
反对 回复 2019-06-06
  • 3 回答
  • 0 关注
  • 1049 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信