2016-08-03 3 views
1

I次のセットアップがあります。パターンマッチングのタイプ情報の使い方は?

trait TypeA { override def toString() = "A" } 
trait TypeB { override def toString() = "B" } 
trait TypeC { override def toString() = "C" } 

def foo[T](t: T) = println(t) 

は今、私はこのような何かを行うことができます。

val valueB: Any = new TypeB {} 

val typedValue = valueB match { 
    case t: TypeA => foo(t) 
    case t: TypeB => foo(t) 
    case t: TypeC => foo(t) 
} 
// prints "B" 

私はこのパターンマッチングブロックを一般化したい場合は、私は単純に行うことができます。

val typedValue = valueB match { 
    case t => foo(t) 
} 

と動作します。しかし、私の実際のユースケースでは、それを推論する関数の引数がないので、メソッドを呼び出すときに型情報を明示的に記述する必要があります。したがってfoo()が型パラメータTでパラメータ化された一般的なメソッドであるが、その型の実際のパラメータが推測されない場合は、これを一般的に1つのcase文(おそらくReflection APIを使用)と一致するパターンに一般化できますか?

これを一般化するにはどうすればよいですか?私はこのパターンマッチングブロックを一般化したい場合は

val typedValue = valueB match { 
    case t: TypeA => foo[TypeA]() 
    case t: TypeB => foo[TypeB]() 
    case t: TypeC => foo[TypeC]() 
    ... 
} 
+2

これはコンパイルするように見える: '場合、T => fooの[t.type]( ) 'それを試してみてください。 – jwvh

+0

タフな部分は、パターンマッチングを実際のタイプを実際に抽出する方法ですか?私は 'val t:Any = ... 'と言うことができたいと思います。パターンマッチングの部分では、実際のタイプと一致します。編集された質問を参照してください(val valueBは現在Any型です)。 'valueB'が' Any'型であると宣言されていれば、残念なことにあなたの提案はうまくいかず、奇妙なメッセージもあります(不特定の値パラメータ:t.type)。 – slouc

答えて

1

は、私は単純に行うことができます。一般的には

val typedValue = valueB match { 
    case t => foo(t) 
} 

あなたがすることはできません。例えば。 foo(x: TypeA),foo(x: TypeB)およびfoo(x: TypeC)が別々の過負荷である場合これは実際のコードの状況です。JsObjectなどの別のメソッドを記述する必要があります。なぜなら、これらの呼び出しはちょうど同じ名前になるからです。 foo(x: JsValue)またはfoo[T <: JsValue](x: T)と書くことはできません。これは避けたいものと同じものを使わずに行います。あなたは、単一のポリモーフィックメソッドを持っていない場合は

:ジェネリック引数が消去されますので、あなたがdef foo[T]() = ...foo[TypeA]()foo[TypeB]()foo[TypeC]()は同じ実際のコードを実行します持っている場合(これはclassOfisInstanceOfまたはasInstanceOfには適用されません。これらは唯一の例外であり、実際には一般的な方法ではないためです)。したがって、foo[<type-of-valueB>]に電話することができます。それらが異なるように、fooは暗黙の引数を持たなければならず、これはTに依存します。この場合

trait Baz[A] { ... } 
object Baz { 
    implicit val bazTypeA: Baz[TypeA] = ... 
    ... 
} 

def foo[A]()(implicit baz: Baz[A]) = ... 

分岐を回避する方法が同じ暗黙を受け入れるfooを呼び出す方法のためのものである:

def bar[A](value: A)(implicit baz: Baz[A]) = foo[A]() 

bar(new TypeA) // uses bazTypeA 
+0

これはどのように機能するのですか?これはPlay JSONを使用したスニペットです。もしあなたがそれに慣れていなければ、とにかくポイントを得るでしょう。JsNumberとJsStringは実行時に解決されないので、消去する必要がありますか? 'val result = json match {case jsString:JsString => json.as [JsNumber]。値が} // と 'ヴァル結果= JSON整合をwork'ない{場合jsString:JsString => json.as [JsString] .VALUE} // works' 一つ期待、二つの呼び出し、' [JsString] 'と' [JsNumber] 'として、あなたが言ったのと同じコードをトリガします。しかし、typeパラメータは大きな違いをもたらします。 – slouc

+1

'as'は暗黙的な引数を使います。これは私の答えの最後にあります。 –

+0

ああ。ありがとう! – slouc

関連する問題