2012-06-20 13 views
17

मान लीजिए मैं निम्नलिखित प्रकारकैसे निर्धारित करने के लिए एक प्रकार पैरामीटर एक विशेषता है की एक उप-प्रकार है कि क्या?

class Foo 
trait Bar 

वहाँ एक तरीका है जिसके एक प्रकार पैरामीटर, टी में ले जाता है, और निर्धारित करते हैं कि टी एक बार है के लिए एक रास्ता है? उदाहरण के लिए,

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

दुःख की बात है isBar[Foo with Bar]false है क्योंकि विलोपन mixins को मिटाने के लिए लगता है।

इसके अलावा, manifest[Foo with Bar] <:< manifest[Bar] गलत है

बिल्कुल यह संभव है?

मैं इस सवाल को देखा: How to tell if a Scala reified type extends a certain parent class?

लेकिन यह है कि इस सवाल का जवाब लक्षण में मिश्रित-साथ काम नहीं करता के रूप में वे के रूप में ऊपर सबूत मिटाया जा लगते हैं।

उत्तर

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 प्रदान करते हैं: स्काला प्रकार के 1 अनुवाद क्योंकि वे प्रकार संकलक जानता है प्रतिनिधित्व करते हैं। इसलिए वे बहुत सादे पुराने प्रकट होता है अधिक से अधिक शक्तिशाली हैं:

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 [बार साथ फू]' (2.10 में <बहुत पसंद 'Predef.manifest') के लिए' 'परोक्ष [TypeTag [बार] के साथ फू] उपयोगी आशुलिपि है। शॉर्टकट की –

+0

भाषण, 'typeof [टी]' 'typeTag [टी] .tpe' के बराबर है। –

6

यह इस पूर्व 2.10 करने के लिए संभव है, बस नहीं:

scala> val fooBar = typeTag[Foo with Bar] 
fooBar: reflect.runtime.universe.TypeTag[Foo with Bar] = TypeTag[Foo with Bar] 
विधि tpe साथ

हम Scalas नई परावर्तन तक पूर्ण पहुंच (जहां तक ​​मुझे पता है) प्रकट होता है:

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

आप 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 
0

एक और typeclass उपयोग (अधिक सामान्य):

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 

अब, आरईपीएल में:

@ 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 अब संबंधित स्केला को रों पैकेज को दर्शाते हैं। एक अतिरिक्त निर्भरता इसका इस्तेमाल करने के जोड़ने की जरूरत है।

संबंधित मुद्दे