繁体   English   中英

如何确定类型参数是否是特征的子类型?

[英]How to determine whether a type parameter is a subtype of a trait?

假设我有以下类型

class Foo
trait Bar

有没有办法制作一个接受Type参数T的方法,并确定该T是否为Bar? 例如,

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

可悲的是, isBar[Foo with Bar]false因为擦除似乎抹去了mixins。

此外, manifest[Foo with Bar] <:< manifest[Bar]为false

这有可能吗?

我看了这个问题: 如何判断Scala的具体类型是否扩展了某个父类?

但是这个答案不适用于混合特征,因为它们似乎被清除,如上所述。

这可以通过TypeTag (至少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提供Scala类型的1:1转换,因为它们代表编译器知道的类型。 因此它们比普通的旧Manifest强大得多:

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

使用方法tpe我们可以完全访问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  

有可能在2.10之前做到这一点,而不是(据我所知)有清单:

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

这有点像黑客,但它可以按照需要运行。

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

scala> isBar[Foo]
res1: Boolean = false

您可以使用类型类来解决它而无需反射:

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

另一个类型类用法(更通用):

  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

现在,在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现在属于scala reflect包。 需要添加额外的依赖项才能使用它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM