2013-04-19 4 views
5

Non ho davvero questo piccolo coso. Ho una classe astratta Box con diverse sottoclassi per diversi tipi. Per esempioCome utilizzare l'estrattore in polimorfico non valido?

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

Il metodo apply nell'oggetto compagno per Box è semplice:

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

così posso scrivere

val sb = Box("StringBox) 

Va bene, la scrittura unapply fa qualche problema. La mia prima idea era di usare il pattern matching del tipo, in questo modo questo:

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 

}

Il che semplicemente non funziona a causa di tipo cancellature.

Il secondo tentativo era una casella generica [T] con tipo T e un membro di tipo astratto ridefinito in ogni sottoclasse. Per esempio:

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

Di conseguenza, posso ri scrivere il mio unapply come:

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 

Purtroppo, questo non funziona neanche. Quindi immagino che anche il riferimento esplicito al tipo in Box [String] venga cancellato, quindi ho bisogno di usare invece un tipo manifest. Forse qualcosa di simile:

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

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

Questo codice compila (2.10), ma ancora non lo fa la conversione implicita desiderato. Perché?

Domanda semplice, esiste un modo per eseguire l'estrazione dei valori senza utilizzare la riflessione o un manifest?

Ciò che veramente mi fa impazzire è la domanda se esiste un modo semplice (r) per combinare il polimorfismo e la corrispondenza del modello? In caso contrario, ci sono altri modi in Scala per realizzare un effetto simile?

Qualche idea o suggerimento?

Grazie mille.

risposta

5

Prolly si può provare questo .. :)

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) 
    } 

È possibile utilizzarlo come -

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

Sì, questo è tutto. Grazie. –

+0

Il tuo benvenuto .. :) – Shrey