避免模​​式匹配中的类型转换

时间:2011-07-23 17:20:56

标签: scala pattern-matching type-erasure

给出一个假设的可变链表(让我们假设这是一个给定的结构 - 所以没有关于改变它的建议,请):

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

CListT中是不变的,所以应该有办法实现这个目标吗?

1 个答案:

答案 0 :(得分:4)

您可以尝试定义提取器:

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