No puede comparar tipos directamente, porque no hay nada allí para comparar (en tiempo de ejecución, debido a erasure). Se podría trabajar en una representación de su clase:
trait TraitA { }
trait TraitB { }
class ClassA extends TraitA { }
class ClassB extends TraitB { }
def myFunc[T](clazz: Class[T]) = {
if (classOf[TraitA] isAssignableFrom clazz) println("A")
else if (classOf[TraitB] isAssignableFrom clazz) println("B")
else println("?")
}
scala> myFunc(classOf[ClassA])
A
scala> myFunc(classOf[String])
?
o que pueda coincidir con el patrón en instancias de la clase:
def myFunc2[T](t: T) = t match {
case _: TraitA => println("A")
case _: TraitB => println("B")
case _ => println("?")
}
scala> myFunc2(new ClassA)
A
scala> myFunc2(Some(5))
?
También puede utilizar el primer enfoque de una manera sintácticamente menos molesto a través de clases manifiesta:
def myFunc3[T](implicit mf: ClassManifest[T]) = {
val clazz = mf.erasure
if (classOf[TraitA] isAssignableFrom clazz) println("A")
else if (classOf[TraitB] isAssignableFrom clazz) println("B")
else println("?")
}
scala> myFunc3[ClassA]
A
scala> myFunc3[String]
?
y se puede elegir diferentes tipos de expedición también si el if/else se convierte en manejable:
object MyFunc {
val dispatch = Map(
classOf[TraitA] -> (() => println("A")),
classOf[TraitB] -> (() => println("B"))
)
val default =() => println("?")
def apply[T](implicit mf: ClassManifest[T]) =
dispatch.find(_._1 isAssignableFrom mf.erasure).map(_._2).getOrElse(default)()
}
scala> MyFunc[ClassA]
A
scala> MyFunc[String]
?
Tenga en cuenta que cualquier código genérico que utilice esto tendrá que tener un manifiesto de clase disponible (ya sea como un parámetro implícito o en forma abreviada, [T: ClassManifest]
.
De hecho encontré 2 maneras que funcionan bien en mi caso: 1) classOf [TraitA] isAssignableFrom clazz como sugeriste 2) if (mf <:
codefly
+1: al principio me molestó tanto con su respuesta como con Scala ("No se pueden comparar tipos directamente, porque no hay ** nada * * hay para comparar "... Hay un ** tipo **, y un tipo es ciertamente algo. Deberías haber escrito" no hay ningún * valor * "en mi humilde opinión. Pero luego explicaste sobre los manifiestos de clase, y eso dio en el clavo. ¡Así que gracias! – rsenna
@rsenna - Con "no hay nada" quise decir que no hay nada allí _en tiempo de ejecución_ porque 'T' solo le dice al compilador cómo debe mantener sus tipos en línea recta en tiempo de compilación. Entonces en realidad ... un tipo genérico es, en tiempo de ejecución, nada. Se fue. ("Borrado de tipo.") Los manifiestos proporcionan una forma de suministrar esa información en tiempo de compilación en tiempo de ejecución. ('ClassTag' o' TypeTag' es la nueva forma de hacerlo en 2.10, aunque la forma antigua todavía funciona.) De todos modos, me alegro de que la haya encontrado útil incluso si mi fraseología no fue muy discreta. –