2012-04-15 5 views
1

Stellen Sie sich eine Klasse A vor, die abstrakt ist und eine Reihe von Fallklassen aufweist. Wir wissen nicht, wie viele festgelegte Klassen oder sogar der Name dieser Fallklassen ist.Deklarieren einer Methode zum Akzeptieren einer unbekannten Fallklasse als Argument für die Verwendung in der Mustererkennung in Scala

abstract class A(field: String) 
//Example of a case class that extends A 
case class B(f: String) extends A(f) 

Jetzt habe ich dies:

a match { 
    case B(f) => println("f") 
} 

Und ich möchte ein Argument in ein Verfahren der Fall Klassentyp zu übergeben. Der Grund, warum ich das möchte, ist, weil ich einen Satz von Regeln in einer Datei konfigurieren werde. Und ich möchte diese Regeln laden und Mustererkennung mit einigen Informationen verwenden, die diese Regeln bieten. Ich möchte so etwas tun:

def printer (a: A, B: A) = { 
    a match{ 
     case B(f) => println("f") 
    } 
} 

Ist das möglich?

Wenn es nicht so einfach ist, kann ich eine abstrakte Klasse im Mustervergleich verwenden? Es wäre perfekt, wenn ich einfach die abstrakte Klasse verwenden könnte, da sie die Hauptstruktur aller Fallklassen hat.

EDIT:

vergessen, dass die Fallklassen zu erwähnen, kann verschiedene Argumente haben, so wäre es gut, etwas zu verwenden, basierend auf der Klasse A (da kann ich meine Muster mit dem Feld passend tun nur)

+0

[Sie werden wahrscheinlich mehr konstruktive Antworten bekommen, wenn Sie mehr über erklären, was Sie * wirklich * zu erreichen versuchen.] (Http://homepage.ntlworld.com/jonathan. deboynepollard/FGA/put-down-the-chocolate-baned-banane.html) –

+0

Ich stimme dir zu, aber wenn ich das tue, wird das zu einer Art riesigen Post. So konzentriere ich mich nur auf das Notwendige. –

Antwort

5

Nicht wie du es versucht hast. Aber wenn Sie verwenden ein Manifest als Kontext gebunden, können Sie es funktioniert:

scala> trait Foo 
defined trait Foo 

scala> case class Bar(baz: String) extends Foo 
defined class Bar 

scala> def boo[A <: Foo : Manifest](foo: Foo) = 
    | if (foo.getClass isAssignableFrom manifest[A].erasure) "foo" else "boo" 
boo: [A <: Foo](foo: Foo)(implicit evidence$1: Manifest[A])java.lang.String 

scala> boo[Foo](Bar("")) 
res0: java.lang.String = boo 

scala> boo[Bar](Bar("")) 
res1: java.lang.String = foo 
+0

"Manifest als Kontext gebunden". Kein idea was das bedeutet: p. Entweder kann ich es nicht in Mustervergleich verwenden ... –

1

Sie können unapply Methode aus dem Begleitobjekt Ihres Falles Klasse extrahieren und verwenden es:

scala> :paste 
// Entering paste mode (ctrl-D to finish) 

abstract class A(field: String) 
case class B(f: String) extends A(f) 
case class C(f: String) extends A(f) 
case class E(f: String, f1: Int) extends A(f) 
case class F(f: String, f1: Int) extends A(f) 

class Unapplyer[T: Manifest, R](f: T => Option[R]) { 
    def unapply(a: Any): Option[R] = { 
    if (manifest[T].erasure.isInstance(a)) f(a.asInstanceOf[T]) else None 
    } 
} 

def printer[T: Manifest, R](a: A, b: T => Option[R]) { 
    val P = new Unapplyer(b) 
    a match { 
    case P((f, f1)) => println(f + " - " + f1) 
    case P(f) => println(f) 
    case _ => println("oops") 
    } 
} 

// Exiting paste mode, now interpreting. 

defined class A 
defined class B 
defined class C 
defined class E 
defined class F 
defined class Unapplyer 
printer: [T, R](a: A, b: (T) => Option[R])(implicit evidence$2: Manifest[T])Unit 

scala> printer(B("test"), B.unapply _) 
test 

scala> printer(B("test"), C.unapply _) 
oops 

scala> printer(E("test", 1), E.unapply _) 
test - 1 

scala> printer(E("test", 1), F.unapply _) 
oops 

scala> printer(E("test", 1), B.unapply _) 
oops 

UPD: Zusätzliche Verwendung mit einer Variablennummer und einem Argumenttyp.

+0

Obwohl ich nicht verstehe, was machst du in der Klasse Unapplyer ich glaube, ich vergaß zu erwähnen, dass Fall Klassen eine variable Anzahl von Argumenten haben können. Und in Ihrer Lösung scheint es sehr argumentabhängig zu sein? –

+0

@TiagoAlmeida: Sie können die Fallklasse mit einer beliebigen Anzahl von Argumenten verwenden, da die 'unapply' Methode' TupleN' zurückgibt. Ich habe meine Antwort aktualisiert. – senia

+0

@TiagoAlmeida: Klasse 'Unapplyer' implementiert eine Art" manuelles Mustervergleich ". 'apply' -Methode überprüft den Typ des Arguments: Wenn es passt, wird die innere 'unapply'-Funktion verwendet, andernfalls ist die Übereinstimmung fehlgeschlagen. – senia

0

Ich verstehe nicht, warum Sie den Typ in die Methode übergeben möchten. Wenn Sie den Mustervergleich verwenden, überprüfen Sie den Typ trotzdem. Warum also es weitergeben? Sie können einfach schreiben

abstract class A(field: String) 
case class B(f: String) extends A(f) 
case class C(i: Int) extends A(i.toString) 

def printer (a: A) = { 
    a match{ 
     case B(f) => println(f) 
     case C(i) => println(i) 
    } 
} 
+0

Problem ist, dass ich nicht weiß, welche Fallklassen ich zuordnen möchte. Stellen Sie sich vor, Sie laden den Mustervergleich aus einer Datei ... Wie können Sie eine Methode entwickeln, die akzeptiert, welche Fallklassen Sie verwenden? –