2013-04-19 9 views
5

Naprawdę nie dostaję tej małej rzeczy. Mam abstrakcyjne pole klasy z kilkoma podklasami dla różnych typów. Na przykładJak korzystać z ekstraktora w postaci polimorficznej Unapply?

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

Sposób zastosowania w obiekcie towarzysz do puszki jest prosta:

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

więc mogę napisać

val sb = Box("StringBox) 

Okay, pisanie Wycofywanie sprawia pewne problemy. Moim pierwszym pomysłem było użycie dopasowywania wzorca typu, jak to w ten sposób:

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 

}

który po prostu nie działa, ponieważ typu wymazywania.

Druga próba była generycznym polem [T] z typem T i abstrakcyjnym elementem typu ponownie zdefiniowanym jako w każdej podklasie. Na przykład:

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

konsekwencji mogę ponownie napisać moje Wycofywanie jak:

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 

Niestety, to nie działa. Więc domyślam się, że jawny typ odniesienia w Box [String] zostaje wymazany, więc potrzebuję użyć zamiast tego manifestu typu. Może coś takiego:

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

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

Ten kod kompiluje (2,10), ale nadal nie pożądany niejawna konwersja. Dlaczego?

Proste pytanie, czy istnieje sposób na ekstrakcję wartości bez użycia odbicia lub manifestu?

To, co mnie naprawdę dręczy, to pytanie, czy istnieje prosty (r) sposób na połączenie polimorfizmu i dopasowywania wzorców w postaci ? Jeśli nie, czy inne sposoby w Scali na osiągają podobny efekt?

Masz pomysł lub sugestie?

Dziękuję bardzo.

Odpowiedz

5

naprawde można spróbować .. :)

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

Można go używać jako -

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

Tak, to wszystko. Dziękuję Ci. –

+0

Twoje powitanie .. :) – Shrey