[英]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.