如何绕过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?!

为什么,我怎么才能避开它?


千万里不及你
浏览 1044回答 3
3回答

杨魅力

这个答案使用Manifest-API,它在Scala2.10中被废弃。请参阅下面的答案,以获得更多最新解决方案。Scala是使用TypeErasure定义的,因为Java虚拟机(JVM)与Java不同,没有泛型。这意味着,在运行时,只有类存在,而不是其类型参数。在本例中,JVM知道它正在处理scala.collection.immutable.List,但不是将此列表参数化为Int.幸运的是,Scala中有一个特性可以让您绕过它。是因为舱单..Manifest是一个类,其实例是表示类型的对象。由于这些实例是对象,所以可以传递它们、存储它们,并通常对它们调用方法。在隐式参数的支持下,它成为一种非常强大的工具。例如,以下面的例子为例:object&nbsp;Registry&nbsp;{ &nbsp;&nbsp;import&nbsp;scala.reflect.Manifest &nbsp;&nbsp;private&nbsp;var&nbsp;map=&nbsp;Map.empty[Any,(Manifest[_],&nbsp;Any)]&nbsp; &nbsp;&nbsp;def&nbsp;register[T](name:&nbsp;Any,&nbsp;item:&nbsp;T)(implicit&nbsp;m:&nbsp;Manifest[T])&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;map&nbsp;=&nbsp;map.updated(name,&nbsp;m&nbsp;->&nbsp;item) &nbsp;&nbsp;} &nbsp;&nbsp;def&nbsp;get[T](key:Any)(implicit&nbsp;m&nbsp;:&nbsp;Manifest[T]):&nbsp;Option[T]&nbsp;=&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;map&nbsp;get&nbsp;key&nbsp;flatMap&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;(om,&nbsp;s)&nbsp;=>&nbsp;if&nbsp;(om&nbsp;<:<&nbsp;m)&nbsp;Some(s.asInstanceOf[T])&nbsp;else&nbsp;None &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;}}scala>&nbsp;Registry.register("a",&nbsp;List(1,2,3))scala>&nbsp;Registry.get[List[Int]]("a")res6:&nbsp;Option[List[Int]]&nbsp;=&nbsp;Some(List(1,&nbsp;2,&nbsp;3))scala &nbsp;&nbsp;>&nbsp;Registry.get[List[String]]("a")res7:&nbsp;Option[List[String]]&nbsp;=&nbsp;None在存储元素时,我们也会存储其中的“报表”。Manifest是一个类,其实例表示Scala类型。这些对象比JVM具有更多的信息,这使我们能够测试完整的参数化类型。不过,请注意,aManifest仍然是一个不断发展的特征。作为其局限性的一个例子,它目前对方差一无所知,并且假设一切都是协变的。我希望一旦完成目前正在开发的Scala反射库,它将变得更加稳定和可靠。

白猪掌柜的

您可以使用Typeable类型类无形为了得到你想要的结果,REPL样本会话,scala>&nbsp;import&nbsp;shapeless.syntax.typeable._import&nbsp;shapeless.syntax.typeable._ scala>&nbsp;val&nbsp;l1&nbsp;:&nbsp;Any&nbsp;=&nbsp;List(1,2,3)l1:&nbsp;Any&nbsp;=&nbsp;List(1,&nbsp;2,&nbsp;3)scala>&nbsp;l1.cast[List[String]]res0:&nbsp;Option[List[String]]&nbsp;=&nbsp;Nonescala >&nbsp;l1.cast[List[Int]]res1:&nbsp;Option[List[Int]]&nbsp;=&nbsp;Some(List(1,&nbsp;2,&nbsp;3))这个cast在此范围内,操作将尽可能精确地擦除wrt。Typeable实例可用。
打开App,查看更多内容
随时随地看视频慕课网APP