带有参数化类型的 Scala asInstanceOf [英] Scala asInstanceOf with parameterized types

查看:47
本文介绍了带有参数化类型的 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]] 不会.在后一个例子中,因为类型参数作为编译的一部分被擦除,所以不可能检查列表的内容是否是请求的类型.

Note that the success of a cast at runtime is modulo Scala's erasure semantics. Therefore the expression 1.asInstanceOf[String] will throw a ClassCastException at runtime, while the expression List(1).asInstanceOf[List[String]] will not. In the latter example, because the type argument is erased as part of compilation it is not possible to check whether the contents of the list are of the requested type.

如果您主要担心在错误的可遍历转换上快速失败,这可能是从 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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆