带有参数化类型的

带有参数化类型的

本文介绍了带有参数化类型的 Scala asInstanceOf的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想编写一个转换为类型 A 的函数,其中 A 可以是例如List[Int],或者更复杂的参数化类型,如 Map[Int, List[Int]].

I would like to write a function that casts to type A, where A can be e.g. List[Int], or a more complicated parameterized type like Map[Int, List[Int]].

def castToType[A](x: Any): A = {
  // throws if A is not the right type
  x.asInstanceOf[A]
}

现在,由于类型擦除(我相信),即使类型不正确,代码也能正常工作.该错误仅在访问时出现,带有 ClassCastException.

Right now, due to type erasure (I believe), the code merrily works even when the type is not correct. The error only manifests on access, witha ClassCastException.

val x = List(1, 2, 3)
val y = castToType[List[String]](x)
y(0) --> throws java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

有什么方法可以使用清单来使其正常工作?谢谢!

Is there a way I can use manifests to make this work properly? Thanks!

推荐答案

不幸的是,这是 asInstanceOf 的固有限制.我真的很惊讶地看到 scaladoc 在 详细信息中提到它一个>:

Unfortunately, this in an inherent limitation of asInstanceOf. I'm actually surprised to see the scaladoc mention it in details:

请注意,运行时强制转换的成功是模 Scala 的擦除语义.因此,表达式 1.asInstanceOf[String] 将在运行时抛出 ClassCastException,而表达式 List(1).asInstanceOf[List[String]] 不会.在后一个例子中,因为类型参数作为编译的一部分被擦除,所以不可能检查列表的内容是否是请求的类型.

如果您主要担心在错误的可遍历转换上快速失败,这可能是从 DB/memcached 接口取回内容时的主要问题,我正在尝试强制对可遍历对象进行头部转换:

If you're mainly concerned about failing fast on wrong cast for traversable which would likely be the main issue when getting stuff back from your DB/memcached interface, I was playing around forcing a cast of the head for traversable objects:

def failFastCast[A: Manifest, T[A] <: Traversable[A]](as: T[A], any: Any) = {
  val res = any.asInstanceOf[T[A]]
  if (res.isEmpty) res
  else {
    manifest[A].newArray(1).update(0, res.head) // force exception on wrong type
    res
  }
}

在一个简单的例子中它有效:

On a simple example it works:

scala> val x = List(1, 2, 3): Any
x: Any = List(1, 2, 3)

scala> failFastCast(List[String](), x)
java.lang.ArrayStoreException: java.lang.Integer
[...]

scala> failFastCast(List[Int](), x)
res22: List[Int] = List(1, 2, 3)

不是更复杂的:

val x = Map(1 -> ("s" -> 1L)): Any
failFastCast(Map[Int, (String, String)](), x) // no throw

我想知道是否有一种方法可以递归地向下钻取到 A 以继续强制转换,直到没有更多类型参数...

I wonder if there is a way to recursively drill down into A to keep casting until there is no more type parameters...

这篇关于带有参数化类型的 Scala asInstanceOf的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!