2012-06-20 12 views
17

さんが言ってみましょう私持って、次の種類型パラメーターが型のサブタイプであるかどうかを調べる方法は?

class Foo 
trait Bar 

Typeパラメータ、Tで受け取るメソッドを作成し、そのTがバーであるかどうかを判断する方法はありますか?消去がミックスインを消去するようなので例えば、

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

悲しいことに、isBar[Foo with Bar]falseです。

また、manifest[Foo with Bar] <:< manifest[Bar]

がすべてで、このことは可能です偽ですか?

私はこの質問を見て:How to tell if a Scala reified type extends a certain parent class?

が、それらは上記の証明されたように消去されているように見えるように、その答えは、混入した形質に動作しません。彼らは、コンパイラが知っているタイプを表すため、Scalaの型の1翻訳:

答えて

20

これはTypeTags(少なくとも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は1を提供しています。したがって、彼らははるかに強力な昔ながらのマニフェストよりも、次のとおりです。メソッドtpe

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

我々は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

'typeTag [Foo with Bar]'は '暗黙的に[TypeTag [Foo with Bar]]'(<2.10の 'Predef.manifest'によく似ています)に便利です。 –

+0

ショートカットについて言えば、 'typeOf [T]'は 'typeTag [T] .tpe'と同じです。 –

6

ちょうど、この前の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 
3

あなたは使って型クラスで反射することなく、それを解決することができます

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 
0

別の型クラスの使用量を(より一般的な):

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が現在属していますスカラにパッケージを反映させる。 1つは、それを使用するために余分な依存関係を追加する必要があります。

関連する問題