2016-08-03 18 views
1

Ich habe folgendes Setup:Wie verwendet man Typinformationen aus dem Mustervergleich?

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) 

nun etwas tun Ich kann:

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" 

Wenn ich dieses Pattern-Matching-Block verallgemeinern wollen, habe ich einfach tun können:

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

und es wird funktionieren. In meinem realen Anwendungsfall muss ich die Typinformationen beim Aufruf der Methode explizit angeben, da es kein Funktionsargument gibt, aus dem sie abgeleitet werden könnte. Also wenn foo() war eine generische Methode mit Parameter T parameterisiert, aber ohne tatsächliche Parameter dieses Typs aus zu folgern, kann ich dies in ein Muster mit nur einer Case-Anweisung verallgemeinern (wahrscheinlich mit der Reflection API)?

Also, wie verallgemeinern?

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

Diese zu kompilieren erscheint: 'Fall t => foo [t.type] () 'Probieren Sie es aus. – jwvh

+0

Der schwierige Teil ist, wie man den Mustervergleich wirklich den tatsächlichen Typ extrahieren lässt? Ich würde gerne sagen können "val t: Any = ..." und in dem Pattern-Matching-Teil würde ich auf den tatsächlichen Typ übereinstimmen. Siehe die bearbeitete Frage (val valueB ist jetzt vom Typ 'Any'). Wenn 'valueB' vom Typ' Any' deklariert ist, funktioniert Ihr Vorschlag leider nicht, und auch mit einer seltsamen Nachricht (unspezifizierte Wertparameter: t.type). – slouc

Antwort

1

Wenn ich dieses Pattern-Matching-Block verallgemeinern wollen, kann ich einfach tun:

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

In der Regel können Sie nicht. Z.B. wenn foo(x: TypeA), foo(x: TypeB) und foo(x: TypeC) sind separate Überlastungen. Und das ist die Situation für Ihren echten Code: Sie müssten separate Methoden für JsObject usw. schreiben, weil diese value Anrufe zufällig denselben Namen haben; Sie können foo(x: JsValue) oder foo[T <: JsValue](x: T) nicht schreiben, die tun würden, was Sie wollen (ohne die gleiche Übereinstimmung, die Sie vermeiden möchten).

In dem Fall, dass Sie eine einzelne polymorphe Methode tun haben: weil generische Argumente gelöscht erhalten, wenn Sie def foo[T]() = ..., haben foo[TypeA](), foo[TypeB]() und foo[TypeC]() den gleichen tatsächlichen Code ausführen (dies gilt nicht für classOf, isInstanceOf oder asInstanceOf , aber das sind die einzigen Ausnahmen und es ist, weil sie nicht wirklich generische Methoden sind). Sie können also einfach foo[<type-of-valueB>] anrufen. Damit sie unterschiedlich sind, muss foo ein implizites Argument haben, das von T abhängt, z.

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

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

In diesem Fall wird die Art und Weise Verzweigung für das Verfahren zu vermeiden, ist foo Aufruf der gleichen impliziten zu akzeptieren:

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

bar(new TypeA) // uses bazTypeA 
+0

Können Sie erklären, wie das funktioniert? Es ist ein Ausschnitt mit Play JSON; Wenn Sie sich nicht damit auskennen, werden Sie den Punkt trotzdem bekommen. Werden JsNumber und JsString zur Laufzeit nicht aufgelöst und sollten daher gelöscht werden? 'val Ergebnis = json Übereinstimmung {Fall jsString: JsString => json.as [JsNumber].Wert} // Werk' nicht und 'val result = json Spiel {case jsString: JsString => json.as [JsString] .value} // works' Man würde erwarten, dass zwei Anrufe,' als [JsString] 'und' as [JsNumber] ', triggern Sie den gleichen Code wie Sie sagten. Aber der Typparameter macht einen großen Unterschied. – slouc

+1

'as' verwendet ein implizites Argument, das am Ende meiner Antwort behandelt wird. –

+0

Oh richtig. Vielen Dank! – slouc