17

次のタイプがあるとしましょう

class Foo
trait Bar

Type パラメータ T を受け取り、その T が Bar であるかどうかを判断するメソッドを作成する方法はありますか? 例えば、

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

悲しいことに、消去isBar[Foo with Bar]falseミックスインを消去するように見えるためです。

また、manifest[Foo with Bar] <:< manifest[Bar]偽です

これはまったく可能ですか?

私はこの質問を見ました: Scala の具体化された型が特定の親クラスを拡張するかどうかを確認する方法は?

しかし、その答えは、上記のように消去されているように見えるため、混合された特性では機能しません。

4

4 に答える 4

22

これは、 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

TypeTagは、コンパイラが認識している型を表すため、Scala型の1:1変換を提供します。したがって、それらは単純な古いマニフェストよりもはるかに強力です。

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

この方法tpeで、Scalasの新しいReflectionに完全にアクセスできます。

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  
于 2012-06-20T20:27:12.827 に答える
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
于 2012-06-20T21:33:10.543 に答える
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
于 2012-06-20T22:13:38.830 に答える