utilizada una sintaxis que página programa etiquetas escribe elementos documento cual básica basica basada scala

scala - una - sintaxis de un programa html



¿Cómo determinar si un parámetro de tipo es un subtipo de un rasgo? (4)

Digamos que tengo los siguientes tipos

class Foo trait Bar

¿Hay una manera de hacer un método que tome un parámetro Tipo, T, y determinar si esa T es una Barra? Por ejemplo,

def isBar[T <: Foo: Manifest] = classOf[Bar].isAssignableFrom(manifest[T].erasure)

Lamentablemente, isBar[Foo with Bar] es false porque el borrado parece borrar los mixins.

Además, manifest[Foo with Bar] <:< manifest[Bar] es falso

¿Es esto posible en absoluto?

Miré esta pregunta: ¿Cómo saber si un tipo de Scala reified amplía cierta clase padre?

pero esa respuesta no funciona con rasgos combinados, ya que parecen borrarse como se evidenció anteriormente.


Es posible hacer esto antes de la 2.10, pero no (por lo que sé) con manifiestos:

def isBar[T <: Foo](implicit ev: T <:< Bar = null) = ev != null

Es un poco hack, pero funciona como se desea.

scala> isBar[Foo with Bar] res0: Boolean = true scala> isBar[Foo] res1: Boolean = false


Esto se puede lograr con TypeTags (al menos 2.10M7):

scala> class Foo; trait Bar defined class Foo defined trait Bar scala> import reflect.runtime.universe._ import reflect.runtime.universe._ scala> def isBar[A <: Foo : TypeTag] = typeOf[A].baseClasses.contains(typeOf[Bar].typeSymbol) isBar: [A <: Foo](implicit evidence$1: reflect.runtime.universe.TypeTag[A])Boolean scala> isBar[Foo] res43: Boolean = false scala> isBar[Foo with Bar] res44: Boolean = true

TypeTags proporciona una traducción 1: 1 de los tipos de Scala porque representan los tipos que el compilador conoce. Por lo tanto, son mucho más poderosos que los antiguos manifiestos:

scala> val fooBar = typeTag[Foo with Bar] fooBar: reflect.runtime.universe.TypeTag[Foo with Bar] = TypeTag[Foo with Bar]

Con el método tpe obtenemos acceso completo al nuevo Reflejo de Scalas:

scala> val tpe = fooBar.tpe // equivalent to typeOf[Foo with Bar] tpe: reflect.runtime.universe.Type = Foo with Bar scala> val tpe.<tab><tab> // lot of nice methods here =:= asInstanceOf asSeenFrom baseClasses baseType contains declaration declarations erasure exists find foreach isInstanceOf kind map member members narrow normalize substituteSymbols substituteTypes takesTypeArgs termSymbol toString typeConstructor typeSymbol widen


Otro uso de typeclass (más genérico):

trait SubClassGauge[A, B] { def A_isSubclassOf_B: Boolean } implicit class IsSubclassOps[A](a: A) { def isSubclassOf[B](implicit ev: SubClassGauge[A, B]): Boolean = ev.A_isSubclassOf_B } trait LowerLevelImplicits { implicit def defaultSubClassGauge[A, B] = new SubClassGauge[A, B] { override def A_isSubclassOf_B: Boolean = false } } object Implicits extends LowerLevelImplicits { implicit def subClassGauge[A <: B, B]: SubClassGauge[A, B] = new SubClassGauge[A, B] { override def A_isSubclassOf_B: Boolean = true } } trait Prime class NotSuper class Super extends Prime class Sub extends Super class NotSub

Ahora, en REPL:

@ import Implicits._ import Implicits._ @ (new Sub).isSubclassOf[NotSuper] res29: Boolean = false @ (new Sub).isSubclassOf[Super] res30: Boolean = true @ (new Sub).isSubclassOf[Prime] res31: Boolean = true @ (new Super).isSubclassOf[Prime] res32: Boolean = true @ (new Super).isSubclassOf[Sub] res33: Boolean = false @ (new NotSub).isSubclassOf[Super] res34: Boolean = false

TypeTag ahora pertenece al paquete TypeTag . Uno necesita agregar dependencia adicional para usarlo.


Puedes resolverlo sin reflexión usando typeclasses:

trait IsBar[T] { def apply():Boolean } trait LowerLevelImplicits { implicit def defaultIsBar[T] = new IsBar[T]{ def apply() = false } } object Implicits extends LowerLevelImplicits { implicit def isBarTrue[T <: Bar] = new IsBar[T] { def apply() = true } } def isBar[T<:Foo]( t: T )( implicit ib: IsBar[T] ) = ib.apply() scala> import Implicits._ scala> isBar( new Foo ) res6: Boolean = false scala> isBar( new Foo with Bar ) res7: Boolean = true