2013-05-29 27 views
5

如果我有一个方法...如何使用新的反射API来判断数组的组件类型是否符合类型参数?

def arrayConformsTo[A](as: Array[_]) = ??? 

...这里需要我可以添加语境下界限A。我希望此方法查看Array的组件类型,如果这是A的子类型,则返回true。因此,举例来说:

arrayConformsTo[Int](Array(1, 2, 3)) //returns true 

arrayConformsTo[String](Array(1, 2, 3)) //returns false 

此前2.10,这一切都已经完成如下:

def arrayConformsTo[A: Manifest](as: Array[_]) = 
    ClassManifest.fromClass(as.getClass.getComponentType) <:< manifest[A] 

但是这个现在废弃警告

<console>:8: warning: method <:< in trait ClassManifestDeprecatedApis is deprecated: Use scala.reflect.runtime.universe.TypeTag for subtype checking instead 
     ClassManifest.fromClass(as.getClass.getComponentType) <:< manifest[A] 
                 ^
<console>:8: warning: value ClassManifest in object Predef is deprecated: Use scala.reflect.ClassTag instead 
     ClassManifest.fromClass(as.getClass.getComponentType) <:< manifest[A] 

我的第一个猜测这个编译如下:

scala> def arrayConformsTo[A: reflect.ClassTag](as: Array[_]) = 
    | reflect.ClassTag(as.getClass.getComponentType) <:< implicitly[reflect.ClassTag[A]] 

但是,这给出了一个弃用警告以及

<console>:8: warning: method <:< in trait ClassManifestDeprecatedApis is deprecated: Use scala.reflect.runtime.universe.TypeTag for subtype checking instead 
     reflect.ClassTag(as.getClass.getComponentType) <:< implicitly[reflect.ClassTag[A]] 
               ^

它告诉我使用TypeTag。但是如何?这是否是一个有效的反思问题?


附录:这似乎很好地工作为我所需要的,但它并不适用于AnyVal工作:

scala> def arrayConformsTo[A: reflect.ClassTag](as: Array[_]) = 
    | implicitly[reflect.ClassTag[A]].runtimeClass isAssignableFrom as.getClass.getComponentType 

回答

7

斯卡拉反射API肯定是一个相当迷宫,但至少它是全面的:

import scala.reflect.runtime.{universe => ru} 
def arrayConformsTo[A: ru.TypeTag](as: Array[_]) = { 
    val mirror = ru.runtimeMirror(getClass.getClassLoader) 
    val classSym = mirror.classSymbol(as.getClass.getComponentType) 
    classSym.toType <:< implicitly[ru.TypeTag[A]].tpe 
} 

REPL测试:

scala> arrayConformsTo[Float](Array[Float]()) 
res9: Boolean = true 

scala> arrayConformsTo[Int](Array[Float]()) 
res10: Boolean = false 

scala> arrayConformsTo[AnyVal](Array[Float]()) 
res11: Boolean = true 

scala> arrayConformsTo[AnyVal](Array[Float]()) 
res12: Boolean = true 

scala> arrayConformsTo[Any](Array[Float]()) 
res13: Boolean = true 

scala> arrayConformsTo[Any](Array[Float]()) 
res14: Boolean = true 

scala> arrayConformsTo[AnyRef](Array[Float]()) 
res15: Boolean = false 

scala> arrayConformsTo[AnyRef](Array[Float]()) 
res16: Boolean = false 

(此编辑由OP原因的完整性)

另一种解决方案(不需要scala-reflect.jar),尽管是一个不保留Float <:< AnyVal is true属性是使用ClassTag作为提取:

scala> def arrayConformsTo[A](as: Array[_])(implicit arrayOfA: ClassTag[Array[A]]) 
    | = as match { 
    |  case arrayOfA(_) => true 
    |  case _   => false 
    | } 
+0

太棒了!如果你不介意,我会在接受它之前编辑你的答案以提供另一个解决方案 –

1

这对我的作品W/O任何编译器警告:

def arrayConformsTo[A](as: Array[_])(implicit t:ClassTag[A]) = { 
    ClassTag(as.getClass().getComponentType()) equals t 
} 

然后这打印true然后false

println(arrayConformsTo[Int](Array(1,2,3))) 
println(arrayConformsTo[String](Array(1,2,3))) 
+1

但是,这并不为'AnyVal'也不'Any'工作,就像从oxbow_lakes最新执行情况的附录。 –

+1

好点。我更喜欢你的答案。 – cmbaxter

相关问题