Как использовать экстрактор в полиморфном виде?

Я действительно не понимаю эту маленькую штуковину. У меня есть абстрактный класс Box с несколькими подклассами для разных типов. Например

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

Метод применения в сопутствующем объекте для Box прост:

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

так что я могу написать

    val sb = Box("StringBox)

Ладно, написание неприменяемых проблем. Моя первая идея состояла в том, чтобы использовать сопоставление с образцом для типа, вот так:

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

}

Который просто не работает из-за стирания типа.

Второй попыткой был универсальный Box[T] с типом T и членом абстрактного типа, переопределенным в каждом подклассе. Например:

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

Следовательно, я могу переписать свое неприменение как:

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

К сожалению, это тоже не работает. Поэтому я предполагаю, что явная ссылка на тип в Box[String] также удаляется, поэтому вместо этого мне нужно использовать манифест типа. Может быть что-то вроде:

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

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

Этот код компилирует (2.10), но все еще не делает желаемого неявного преобразования. Зачем?

Простой вопрос, есть ли способ извлечь значение без использования отражения или манифеста?

Что меня действительно поражает, так это вопрос, существует ли простой (r) способ сочетания полиморфизма и сопоставления с образцом? Если нет, есть ли в Scala другие способы достижения подобного эффекта?

Любая идея или предложения?

Большое спасибо.

1 ответ

Решение

Вы можете попробовать это..:)

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

Вы можете использовать его как -

  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 !
Другие вопросы по тегам