Jen*_*olm 3 reflection types casting scala scala-2.10
我在浏览新的2.10版本的Scala(有点稀疏?)文档时遇到了麻烦.我有一种情况,我从没有类型信息的源递归读取数据.在阅读时我知道预期的类型,所以我可以检查该类型是否与传入的数据一致.
我的问题是:当尝试检索具有类型参数的集合对象(例如a Array[Int])时,如何使用期望的类型来确保读取值的类型正确?
到目前为止,我已经摆弄了Scala Api提供的代码,它允许您提取类型参数.我还读到了类标签以及它们如何用于创建数组.所以我的下一个想法是1)找到类型参数,2)从该类型创建一个数组,3)看看读数据是否适合没有例外,如下所示:
val paramType = paramInfo[Array[X]] // Step 1: Find the X type parameter
val array = Array[paramType](size) // Step 2: Can't use TypeTags#Type as a normal Java type...
// Step 3: Feed data into the array and hope for the best
// Step 4: Profit!
Run Code Online (Sandbox Code Playgroud)
由于上面paramType给出了Type,因此将该类型转换为类标记应该是一件简单的事情.但答案不合理我.
说实话,这个解决方案对我来说似乎有些混乱,但我无法弄清楚任何更聪明的东西.如果有其他解决方案,我全都耳朵!
提前致谢.
编辑:为了澄清,我上面的例子应该证明我想从Array [Int]中提取类型X(例如),然后创建一个包含该特定类型的数组的实例.希望更清楚.
编辑:或许可以进一步澄清(我真的让它变得不清楚吗?:-)).我想从数据源中读取一个集合.我希望用正确的,预期的类型输入该集合.所以我想说我称之为方法readData.因为我知道期望什么类型,所以我给它一个预期类型的类型参数.举个例子,假设是Array [Int].它可以是Array [String]或Iterable [Any]或者只是Null或者其他什么.readData调用该方法时,我希望将给定的预期类型(Array [Int])与从外部源读取的数据类型相匹配.如果找到的类型是期望类型的相同类型 - 或子类型 - 我们可以转换并返回数据.如果不是,则抛出异常,通知用户发现的数据不是预期的类型.总结一下:我如何拨打电话readData[Array[Int]]?
编辑:我通过创建一个数组[Any]解决了这个问题,检索了预期的类型(上面的X)并迭代数组以查看元素是否与X的类型(或子类型)相同.如果是,我们可以安全地强制转换为数组[X].在下面的例子中,预期的类型由E表示.我知道,这非常hackish,但是再次:我很想看到替代品......
// Matches if the type of o corresponds (<:<) to the type of x
def verifyType(o : Any, x : Type) : Boolean = { ... }
// Get the type of the array parameter (X)
val tpe = reflect.runtime.universe.typeOf[E] tpe match {
// The returned Type is not an instance of universe.Type - hence the cast
case TypeRef(_, _, args) => args.asInstanceOf[List[Type]]
case _ => throw new IllegalArgumentException("Could not find type parameters in type " + tpe)
}
// Iterate the array and make sure the types match
val hasWrongType = array.exists(e => !verifyType(e, tpe))
if (hasWrongType) throw new Exception(...) // The types does not fit
else array.asInstanceOf[E] // We can safely cast
Run Code Online (Sandbox Code Playgroud)
在Scala 2.10中你真的不需要任何新东西来做这件事,虽然ClassManifest你使用替代品而不是早期版本ClassTag:
def makeArray[T : reflect.ClassTag](length: Int): Array[T] = {
val tTag = implicitly[reflect.ClassTag[T]]
tTag.newArray(length)
}
Run Code Online (Sandbox Code Playgroud)
在REPL中:
scala> makeArray[String](5)
res0: Array[String] = Array(null, null, null, null, null)
Run Code Online (Sandbox Code Playgroud)
原始类型:
scala> makeArray[Int](5)
res1: Array[Int] = Array(0, 0, 0, 0, 0)
Run Code Online (Sandbox Code Playgroud)
编辑:拿两个:
def makeArrayLike(a: Array[_], length: Int): Array[_] = {
val cA = a.getClass
val cC = cA.getComponentType
java.lang.reflect.Array.newInstance(cC, length).asInstanceOf[Array[_]]
}
Run Code Online (Sandbox Code Playgroud)
在REPL中:
scala> val ai1 = Array[Int](1, 2, 3)
ai1: Array[Int] = Array(1, 2, 3)
scala> val as1 = Array[String]("one", "two", "three")
as1: Array[String] = Array(one, two, three)
scala> makeArrayLike(as1, 5)
res0: Array[_] = Array(null, null, null, null, null)
scala> makeArrayLike(ai1, 5)
res1: Array[_] = Array(0, 0, 0, 0, 0)
Run Code Online (Sandbox Code Playgroud)