我有createOld方法,我需要覆盖,我无法改变它.我想使用TypeTag模式匹配提供的类型createNew.我们的目标是找出如何调用createNew的createOld.我目前的理解是编译器没有足够的关于Ain createOld方法的类型信息,如果它还没有TypeTag[A].
object TypeTagFromClass {
class C1
class C2
// How to get TypeTag[A] needed by createNew?
def createOld[A](c: Class[A]): A = createNew ???
def createNew[A : TypeTag]: A = {
val result = typeOf[A] match {
case a if a =:= typeOf[C1] => new C1()
case a if a =:= typeOf[C2] => new C2()
}
result.asInstanceOf[A]
}
}
Run Code Online (Sandbox Code Playgroud)
它可以创建一个TypeTag从Class使用Scala的反射,虽然我不知道这是否执行TypeCreator是绝对正确的:
import scala.reflect.runtime.universe._
def createOld[A](c: Class[A]): A = createNew {
val mirror = runtimeMirror(c.getClassLoader) // obtain runtime mirror
val sym = mirror.staticClass(c.getName) // obtain class symbol for `c`
val tpe = sym.selfType // obtain type object for `c`
// create a type tag which contains above type object
TypeTag(mirror, new TypeCreator {
def apply[U <: Universe with Singleton](m: api.Mirror[U]) =
if (m eq mirror) tpe.asInstanceOf[U # Type]
else throw new IllegalArgumentException(s"Type tag defined in $mirror cannot be migrated to other mirrors.")
})
}
Run Code Online (Sandbox Code Playgroud)
但是,TypeTag如果您不需要检查通用参数和完整的Scala类型信息,则实际上并不需要完整.您可以使用ClassTags:
def createNew[A: ClassTag]: A = {
val result = classTag[A].runtimeClass match {
case a if a.isAssignableFrom(classOf[C1]) => new C1()
case a if a.isAssignableFrom(classOf[C2]) => new C2()
}
result.asInstanceOf[A]
}
Run Code Online (Sandbox Code Playgroud)
或者用一些隐含的糖:
implicit class ClassTagOps[T](val classTag: ClassTag[T]) extends AnyVal {
def <<:(other: ClassTag[_]) = classTag.runtimeClass.isAssignableFrom(other.runtimeClass)
}
def createNew[A: ClassTag]: A = {
val result = classTag[A] match {
case a if a <<: classTag[C1] => new C1()
case a if a <<: classTag[C2] => new C2()
}
result.asInstanceOf[A]
}
Run Code Online (Sandbox Code Playgroud)
您可以使用普通的旧Java newInstance()方法进一步简化:
def createNew[A: ClassTag]: A = classTag[A].runtimeClass.newInstance().asInstanceOf[A]
Run Code Online (Sandbox Code Playgroud)
当然,这只有在您不需要不同类的不同构造函数参数时才有效.
调用这个createNew从createOld比用一个简单得多TypeTagS:
def createOld[A](c: Class[A]): A = createNew(ClassTag[A](c))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1625 次 |
| 最近记录: |