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

Twi*_*dle 17 scala

假设我有以下类型

class Foo
trait Bar
Run Code Online (Sandbox Code Playgroud)

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

def isBar[T <: Foo: Manifest] = 
  classOf[Bar].isAssignableFrom(manifest[T].erasure)
Run Code Online (Sandbox Code Playgroud)

可悲的是,isBar[Foo with Bar]false因为擦除似乎抹去混入.

而且,manifest[Foo with Bar] <:< manifest[Bar]是假的

这有可能吗?

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

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

kir*_*uku 22

这可以通过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
Run Code Online (Sandbox Code Playgroud)

TypeTags提供Scala类型的1:1转换,因为它们代表编译器知道的类型.因此它们比普通的旧Manifest强大得多:

scala> val fooBar = typeTag[Foo with Bar]
fooBar: reflect.runtime.universe.TypeTag[Foo with Bar] = TypeTag[Foo with Bar]
Run Code Online (Sandbox Code Playgroud)

通过该方法,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  
Run Code Online (Sandbox Code Playgroud)

  • 作为脚注:`typeTag [Foo with Bar]`是一个有用的简写,用于`隐式[TypeTag [Foo with Bar]]`(非常类似于<2.10中的'Predef.manifest`). (3认同)

Tra*_*own 6

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

def isBar[T <: Foo](implicit ev: T <:< Bar = null) = ev != null
Run Code Online (Sandbox Code Playgroud)

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

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

scala> isBar[Foo]
res1: Boolean = false
Run Code Online (Sandbox Code Playgroud)