6

如果我有方法...

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

...我可以根据需要添加上下文边界A。我希望此方法查看 的组件类型,Array如果这是 的子类型,则返回 true A。因此,例如:

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
4

2 回答 2

8

scala 反射 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属性是使用 aClassTag作为提取器:

scala> def arrayConformsTo[A](as: Array[_])(implicit arrayOfA: ClassTag[Array[A]]) 
     | = as match {
     |     case arrayOfA(_) => true
     |     case _           => false
     |   }
于 2013-05-29T14:13:14.407 回答
1

这对我有用,没有任何编译器警告:

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)))
于 2013-05-29T14:09:00.047 回答