如何解决Scala上的类型擦除?或者,为什么我无法获取集合的类型参数?

丹尼尔·C·索布拉尔

在Scala上生活的一个可悲的事实是,如果实例化一个List [Int],则可以验证您的实例是一个List,并且可以验证它的任何单个元素是一个Int,而不是它是一个List [可以很容易地验证:

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?!

-unchecked选项将责任完全归咎于类型擦除:

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?!

为什么会这样,我该如何解决?

丹尼尔·C·索布拉尔

此答案使用Manifest-API,从Scala 2.10开始不推荐使用。请参阅下面的答案以获取更多最新解决方案。

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

幸运的是,Scala中有一项功能可以让您解决这个问题。这是清单清单是类,其实例是表示类型的对象。由于这些实例是对象,因此您可以传递它们,存储它们并通常在它们上调用方法。在隐式参数的支持下,它成为一个非常强大的工具。以以下示例为例:

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

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

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何解决此Scala函数参数类型擦除错误?

案例类的Scala类型擦除如何解决

Scala模式匹配功能-如何解决类型擦除

为什么Typescript将我的keyof类型强制为从不类型,我该如何解决?

如何解决所需的类型注释无法推断类型参数“T”的类型?编译这段代码需要什么类型的注解?

使用外接键盘时,为什么AwesomeWM无法识别我的所有modkey按键,或者我该如何解决?

为什么ghci可以看到未导出的类型和构造函数?我该如何解决?

为什么 vstack 会改变元素的类型?我该如何解决这个问题?

尝试检查碰撞时为什么会出现类型错误,我该如何解决?

我如何解决此错误:无法将“NSURL”类型的值转换为预期的参数类型“URLRequest”

是什么导致错误“HAVING 的参数必须是布尔类型,而不是货币类型”,我该如何解决?

什么是“类型不匹配”,我该如何解决?

什么是泛型泛型?它们如何解决“类型擦除”问题?为什么不进行重大更改就不能添加它们?

Scala的类型擦除如何用于更高种类的类型参数?

dart - 如何解决“无法将参数类型“Null”分配给参数类型“MyUser”的问题。

为什么JavaCC无法在我的Mac上运行,该如何解决?

如何获取类中类型参数的擦除类型

为什么会出现Tensorflow错误:发生无法将<class'dict'>类型的对象转换为Tensor的问题,我该如何解决?

为什么在编译时出现“无法将't²'与'f32'类型统一”的提示,我该如何解决?

如何解决无法将类型...的值转换为预期的参数类型inout _

如何解决无法转换“字符串”类型的值?到预期的参数类型“ URL”

'List <dynamic>'不是'List <Comment>'类型的子类型。Dart为什么不能推断出这种类型?我该如何解决?

为什么我会收到“类型测试的重复修饰符”以及如何解决它

如何避免类型参数擦除

为什么Java类型擦除会更改目标集合的非通用类型?

“无法将类型为'System.Byte []'的对象强制转换为类型为'System.IConvertible'。” 照片错误:为什么以及如何解决?

为什么无法解决此类型?

我该如何解决“参数类型”对象?不能分配给参数类型“字符串”

为什么 Xamarin.Android 上的 JSON.NET 永远无法完成解析,我该如何解决?