问题描述
我想编写一个转换为类型 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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!