2011-03-30 5 views
12

私は、特定のタイプのクラスを返すメソッドを持っていると思いますが、私は方法は、以下のようにクラスが特定の形質を拡張するかどうかによって異なる動作をします:Scalaの型パラメータに対してマッチングを実行して、それが特性を実装しているかどうかを確認できますか?

 

case class ClassA extends TraitA 
case class ClassB extends TraitB 
case class ClassC extends TraitA 
... 
def myfunc[T]():T = { 
    T match { 
    case TraitA => // return new T in a particular way 
    case TraitB => // ditto 
    } 
} 
 

が、このことは可能です、私は間違った方法でそれについて行くのですか?

ありがとうございました

答えて

13

タイプを比較することはできません(実行時にはerasureのため)。あなたは、あなたのクラスの表現に仕事ができる:

trait TraitA { } 
trait TraitB { } 
class ClassA extends TraitA { } 
class ClassB extends TraitB { } 

def myFunc[T](clazz: Class[T]) = { 
    if (classOf[TraitA] isAssignableFrom clazz) println("A") 
    else if (classOf[TraitB] isAssignableFrom clazz) println("B") 
    else println("?") 
} 

scala> myFunc(classOf[ClassA]) 
A 

scala> myFunc(classOf[String]) 
? 

たりすることができますクラスのインスタンス上のパターンマッチ:

def myFunc2[T](t: T) = t match { 
    case _: TraitA => println("A") 
    case _: TraitB => println("B") 
    case _ => println("?") 
} 

scala> myFunc2(new ClassA) 
A 

scala> myFunc2(Some(5)) 
? 

ます。また、クラスを経由して文法的に目立たないように、最初のアプローチを使用することができますマニフェスト:

def myFunc3[T](implicit mf: ClassManifest[T]) = { 
    val clazz = mf.erasure 
    if (classOf[TraitA] isAssignableFrom clazz) println("A") 
    else if (classOf[TraitB] isAssignableFrom clazz) println("B") 
    else println("?") 
} 

scala> myFunc3[ClassA] 
A 

scala> myFunc3[String] 
? 

、あなたはまた、発送の異なる種類を選択することができるかどうかの/他のwieldy次のようになります。

あなたはからこれを使用するすべての一般的なコードは(暗黙のパラメータとしてまたは速記、 [T: ClassManifest]のいずれかで利用可能マニフェストクラスを持っている必要がありますことを
object MyFunc { 
    val dispatch = Map(
    classOf[TraitA] -> (() => println("A")), 
    classOf[TraitB] -> (() => println("B")) 
) 
    val default =() => println("?") 
    def apply[T](implicit mf: ClassManifest[T]) = 
    dispatch.find(_._1 isAssignableFrom mf.erasure).map(_._2).getOrElse(default)() 
} 

scala> MyFunc[ClassA] 
A 

scala> MyFunc[String] 
? 

注意。

+0

実際に私の場合はうまくいく2つの方法が見つかりました: 1)classOf [TraitA] isAssignableFrom clazz – codefly

+0

+1:最初はあなたの答えとScalaの両方で迷惑になりました(「タイプが何もないので直接タイプを比較することはできません。 *比較するには "... **タイプ**があり、タイプは確かに何かです。あなたは"値*がありません "と書かれているはずです)。しかし、あなたはクラスのマニフェストについて説明しました。ほんとありがと! – rsenna

+0

@rsenna - "何もありません"という意味は、 'T'はコンパイル時にどのように型をまっすぐに保つべきかをコンパイラに伝えるだけなので、そこには何もありません。実際には...ジェネリック型は、実行時には何もありません。それはなくなった。 (「タイプ消去」。)マニフェストは、コンパイル時の情報を実行時に提供する方法を提供します。 ( 'ClassTag'や' TypeTag'は2.10でそれを行う新しい方法ですが、古い方法はまだ動作しますが)とにかく、私のフレーズがあまり触れられていなくても、あなたは役に立ちました。 –

1

タイプを確認するにはインスタンスが必要です。ジェネリック自体は、型のプレースホルダです。

trait bTrait //common base trait 
trait TraitA extends bTrait 
trait TraitB extends bTrait 

class ClassA extends TraitA 
class ClassB extends TraitB 

def myFunc[T <: bTrait](t:T) : String = //passing explicitly an instance of type T 
{ 
    t match { 
    case _ : TraitA => "TraitA" 
    case _ : TraitB => "TraitB" 
    } 
} 

println(myFunc(new ClassA)) //prints TraitA 
+0

私はインスタンスがあれば、これは簡単だろうと約束しました! – codefly

2

これはほとんど継承の標準的な記述である

を「メソッドはクラスが特定の形質を拡張するかどうかによって異なる動作をしたい」:あなたはこのような何かを行うことができます。あなたは後の異なる振る舞いをカプセル化したそれぞれの特性のメソッドを持つことができませんか?

+0

ここでの主な問題は、オブジェクトのインスタンスがないことです。オブジェクトのタイプに基づいて、私はどこに行けばいいのかを判断する必要があります(この場合はデータベース) – codefly

関連する問題