2013-04-19 13 views
5

Ich bekomme dieses kleine Ding nicht wirklich. Ich habe eine abstrakte Klasse Box mit mehreren Unterklassen für verschiedene Typen. Zum BeispielWie Extraktor in polymorphe nicht anwenden?

abstract class Box 
class StringBox(val sValue : String) extends Box 

Die Methode apply im Begleitobjekt für Box ist einfach:

object Box{ 
    def apply(s: String) = new StringBox(s) 
    def apply(b: Boolean) = new BooleanBox(b) 
    def apply(d: Double) = new DoubleBox(d) 
} 

so kann ich schreiben

val sb = Box("StringBox) 

Okay, das Schreiben Unapply einige Mühe macht. Meine erste Idee war Pattern-Matching von der Art zu verwenden, wie diese dies:

def unapply(b: Box) = b match { 
    case sb: StringBox => Some(sb.sValue) 
    case bb: BooleanBox => Some(bb.bValue) 
    case db: DoubleBox => Some(db.dValue) 
    case _ => None 

}

, die einfach nicht, weil der Typ Löschungen nicht funktioniert.

Zweiter Versuch war eine generische Box [T] mit Typ T und einem abstrakten Typ Mitglied neu definiert in jeder Unterklasse. Zum Beispiel:

abstract class Box[T] {def value : T} 
class StringBox(val sValue : String) extends Box[String] { 
    override def value : String = sValue 
} 

Folglich kann ich wieder meine Unapply schreiben wie:

def unapply[T](b: Box[T]) = b match { 
    case sb: Box[String] => Some(sb.value) 
    case bb: Box[Boolean] => Some(bb.value) 
    case db: Box[Double] => Some(db.value) 
    case _ => None 

Leider ist dies auch nicht funktioniert. Also ich denke, die explizite Typ-Referenz in Box [String] wird auch gelöscht, so dass ich stattdessen eine Typ-Manifest verwenden muss. Vielleicht so etwas wie:

def unapply[T](b: Box[_])(implicit target: Manifest[T]): Option[T] = { 

    if(b.value == target) Some(b.value.asInstanceOf[T]) 
    else None 
} 

Dieser Code kompiliert (2.10), aber immer noch nicht die gewünschte implizite Konvertierung. Warum?

Einfache Frage, gibt es eine Möglichkeit, Wert-Extraktion ohne Verwendung von Reflexion oder ein Manifest zu tun?

Was mich wirklich erschüttert ist die Frage, ob es einen einfachen (r) Weg gibt, Polymorphismus und Mustervergleich zu kombinieren? Wenn nicht, gibt es andere Möglichkeiten in Scala einen ähnlichen Effekt zu erzielen?

Irgendwelche Ideen oder Vorschläge?

Vielen Dank.

Antwort

5

Prolly können Sie dies versuchen .. :)

abstract class Box[T](val v: T) 

    object Box { 
    def apply(s: String) = new StringBox(s) 
    def apply(b: Boolean) = new BooleanBox(b) 
    def apply(d: Double) = new DoubleBox(d) 

    } 

    class StringBox(sValue: String) extends Box(sValue) 
    object StringBox { 
    def unapply(b: StringBox) = Some(b.v) 
    } 

    class BooleanBox(sValue: Boolean) extends Box(sValue) 
    object BooleanBox { 
    def unapply(b: BooleanBox) = Some(b.v) 
    } 

    class DoubleBox(sValue: Double) extends Box(sValue) 
    object DoubleBox { 
    def unapply(b: DoubleBox) = Some(b.v) 
    } 

Sie es als verwenden können -

def useCase[T](box: Box[T]) = box match { 
    case StringBox("StringBoxxx") => "I found the StringBox!" 
    case StringBox(s) => "Some other StringBox" 
    case BooleanBox(b) => { 
      if (b) "Omg! its true BooleanBox !" 
      else "its false BooleanBox :(" 
      } 
    case DoubleBox(x) => { 
       if (x > 3.14) "DoubleBox greater than pie !" 
       else if (x == 3.14) "DoubleBox with a pie !" 
       else "DoubleBox less than a pie !" 
    } 
    case _ => "What is it yaa ?" 
    }            

    useCase(Box("StringBoxxx")) //> res0: String = I found the StringBox! 
    useCase(Box("Whatever !")) //> res1: String = Some other StringBox 
    useCase(Box(true))   //> res2: String = Omg! its true BooleanBox ! 
    useCase(Box(false))   //> res3: String = its false BooleanBox :(
    useCase(Box(4))    //> res4: String = DoubleBox greater than pie ! 
    useCase(Box(3.14))   //> res5: String = DoubleBox with a pie ! 
    useCase(Box(2))    //> res6: String = DoubleBox less than a pie ! 
+0

Ja, das ist es. Vielen Dank. –

+0

Ihre Begrüßung .. :) – Shrey