2012-06-20 45 views
17

Hãy nói rằng tôi có các loại sau đâyLàm thế nào để xác định xem một tham số kiểu là một kiểu con của một đặc điểm?

class Foo 
trait Bar 

Có cách nào để thực hiện một phương pháp mà mất trong một tham số Type, T, và xác định xem T đó là một Bar? Ví dụ,

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

Đáng buồn thay, isBar[Foo with Bar]false vì tẩy xoá dường như xóa mixins.

Ngoài ra, manifest[Foo with Bar] <:< manifest[Bar] là sai

Điều này có thể thực hiện được không?

Tôi nhìn câu hỏi này: How to tell if a Scala reified type extends a certain parent class?

nhưng câu trả lời mà không làm việc với hỗn hợp trong những đặc điểm như họ dường như bị xóa như được minh chứng trên.

Trả lời

20

này có thể đạt được với TypeTags (ít nhất 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 cung cấp 1: dịch 1 trong tổng số các loại Scala vì họ đại diện cho các loại trình biên dịch biết. Do đó họ có nhiều quyền lực hơn Manifests cũ đồng bằng:

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

Với phương pháp tpe chúng tôi được tiếp cận đầy đủ tới Scalas Reflection mới:

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

Là chú thích: 'typeTag [Foo with Bar]' là viết tắt hữu ích cho 'ngầm [TypeTag [Foo with Bar]]' (giống như 'Predef.manifest' trong <2.10). –

+0

Nói về các phím tắt, 'typeOf [T]' tương đương với 'typeTag [T] .tpe'. –

6

Có thể làm được điều này trước 2.10, chỉ cần không (theo như tôi biết) với tệp kê khai:

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

Đó là một chút hack, nhưng nó hoạt động như mong muốn.

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

scala> isBar[Foo] 
res1: Boolean = false 
3

Bạn có thể giải quyết nó mà không suy nghĩ bằng cách sử dụng 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

Một cách sử dụng typeclass (hơn generic):

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 

Bây giờ, trong 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 hiện thuộc về s để scala phản ánh gói. Người ta cần thêm phụ thuộc để sử dụng nó.

Các vấn đề liên quan