2013-05-29 66 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

相關問題