Избежание приведения типов при сопоставлении с образцом - PullRequest
1 голос
/ 23 июля 2011

С учетом гипотетического изменяемого связанного списка (предположим, что это заданная структура - поэтому не нужно вносить предложения по ее изменению):

trait CList[T]
trait CNil [T] extends CList[T]
trait CCons[T] extends CList[T] {
  def head: T
  def tail: CList[T]
}

И учитывая стирание типов в Scala, как я могу выполнить итерацию по нему без приведения:

@annotation.tailrec def lastValue[T](l: CList[T]): Option[T] = l match {
  case _: CNil [_] => None
  case c: CCons[_] => lastValue(c.asInstanceOf[CCons[T]]) // ouch!
}

CList инвариантен в T, поэтому должен быть способ сделать это?

1 Ответ

4 голосов
/ 23 июля 2011

Вы можете попробовать определить экстракторы:

object CNil {
  def unapply[T](clist: CList[T]): Boolean = clist.isInstanceOf[CNil[_]]
}

object CCons {
  def unapply[T](clist: CList[T]): Option[(T, CList[T])] = clist match {
    case _: CNil[_] => None
    case c: CCons[_] => Some(c.head, c.tail)
  }

}

@annotation.tailrec def lastValue[T](l: CList[T]): Option[T] = l match {
  case CNil() => None
  case CCons(head, tail) => lastValue(tail)
}

Возможно, вам придется дать им другое имя, если вы не можете поместить их в те же файлы, что и исходные черты.

С другой стороны, реализация вашей lastValue функции, вероятно, не делает то, что вы ожидаете ... Как насчет этой?

def lastValue[T](clist: CList[T]): Option[T] = {
  @annotation.tailrec
  def lastValue0(prevValue: Option[T], clist: CList[T]): Option[T] =
    clist match {
      case CNil() => prevValue
      case CCons(head, tail) => lastValue0(Some(head), tail)
    }

  lastValue0(None, clist)
}
...