Scala 2.10反射:从一个类型创建一个数组 [英] Scala 2.10 reflection: Creating an Array from a type

查看:168
本文介绍了Scala 2.10反射:从一个类型创建一个数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在探索新版本2.10版本中的Scala(有点稀疏?)文档时遇到问题。我有一种情况,我从源没有类型信息递归地读取数据。在读取时,我知道期望的类型,所以我可以检查该类型是否与传入的数据对齐。

I'm having trouble digging through Scala's (somewhat sparse?) documentation on the new 2.10 release. I have a situation where I am reading data recursively from a source without type information. On the time of reading I know the expected type, so I can check whether that type aligns with the incoming data.

我的问题是:当尝试检索集合对象使用类型参数(例如 Array [Int] ),如何使用期望的类型来确保读取的值是正确的类型?

My problem is: When attempting to retrieve a collection object with type parameters (for instance an Array[Int]), how can I use the expected type to ensure that the read values are of the correct type?

到目前为止,我已经提供了 Scala Api ,允许您提取类型参数。我还阅读了类标签以及如何使用它们来创建数组。所以我的下一个想法是1)找到类型参数,2)从该类型创建一个数组,3)看看读数据是否符合没有异常,如下:

So far I've fiddled around with code provided by the Scala Api that allows you to extract type-parameters. I also read about the Class Tags and how they can be used to create Arrays. So my next thought was to 1) find the type parameter, 2) create an array from that type and 3) see if the read data fits without exceptions, like so:

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!

由于上述 paramType ,它应该是一个简单的事情,将该类型转换为类标签。但是答案解释了我。

Since the above paramType gives me the Type, it should be a simple matter of converting that type to a class tag. But the answer illudes me.

说实话,这个解决方案似乎对我有点凌乱,但我还没有能够找到更聪明的东西。

To be honest this solution seems a bit messy to me, but I haven't been able to figure out anything smarter. If there are alternative solutions I'm all ears!

提前感谢。

编辑:澄清一下,我上面的例子应该演示,我想从Array [Int](例如)提取类型X,然后使一个数组的实例包含该特定类型。希望它变得更清楚。

To clarify, my above example should demonstrate that I want to extract type X from Array[Int] (for example) and then make an instance of an array containing that particular type. Hope that made it clearer.

编辑:也许进一步的澄清是有序的(我真的让它不清楚吗?我想从数据源中读取一个集合。我想要该类型的正确的,期望的类型键入。所以,让我们说,我调用方法 readData 。因为我知道什么类型期望我给它一个类型参数的期望类型。例如,让我们说Array [Int]。它可以是Array [String]或Iterable [Any]或简单的Null或任何。当调用 readData 方法时,我想将给定的预期类型(Array [Int])与从外部源读取的数据的类型进行匹配。如果找到的类型是预期类型的​​相同类型或子类型,我们可以转换和返回数据。如果没有,则抛出异常,通知用户找到的数据不是预期类型。所以总结一下:如何调用 readData [Array [Int]] 工作?

Perhaps further clarification is in order (did I really make it that unclear? :-) ). I want to read a collection from a data-source. And I want that collection to be typed with the correct, expected, type. So let's say I call the method readData. Since I know what type to expect I give it a type parameter of that expected type. As an example, let's say Array[Int]. It could be Array[String] or Iterable[Any] or simply Null or whatever. When the readData method is called, I would like to match the given, expected type (Array[Int]) to the type of the data read from the external source. If the found type is the same type - or a subtype - of the expected type we, can cast and return the data. If not, an exception is thrown, informing the user that the found data wasn't of the expected type. So to sum it up: How do I make a call to readData[Array[Int]] work?

编辑:我解决了这个问题,通过创建一个Array [Any],检索预期的类型(上面的X)和迭代数组,看看元素是否是相同的类型(或子类型)的X.如果是,我们可以安全cast到Array [X]。在下面的例子中,期望的类型由E表示。这很可笑,我知道,但是再次:我很想看到替代...

I solved the issue by creating an Array[Any], retrieve the expected type (X above) and iterate the array to see if the elements are of the same type (or subtype) of X. If they are, we can safely cast to Array[X]. In the example below the expected type is represented by E. It's pretty hackish, I know, but again: I'd love to see alternatives...

// 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


推荐答案

真的需要任何新的Scala 2.10来做这个,虽然而不是早期版本的 ClassManifest 你使用替换, ClassTag

You don't really need anything new in Scala 2.10 to do this, though instead of earlier versions' ClassManifest you use the replacement, ClassTag:

def makeArray[T : reflect.ClassTag](length: Int): Array[T] = {
  val tTag = implicitly[reflect.ClassTag[T]]
  tTag.newArray(length)
}


b $ b

在REPL中:

In the REPL:

scala> makeArray[String](5)
res0: Array[String] = Array(null, null, null, null, null)

有原始类型:

scala> makeArray[Int](5)
res1: Array[Int] = Array(0, 0, 0, 0, 0)

编辑:两个:

def makeArrayLike(a: Array[_], length: Int): Array[_] = {
  val cA = a.getClass
  val cC = cA.getComponentType
  java.lang.reflect.Array.newInstance(cC, length).asInstanceOf[Array[_]]
}



<

In the 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)

这篇关于Scala 2.10反射:从一个类型创建一个数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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