Given a hypothetical mutable linked list (let's assume this is a given structure -- so no suggestions about changing it, please):
trait CList[T]
trait CNil [T] extends CList[T]
trait CCons[T] extends CList[T] {
def head: T
def tail: CList[T]
}
And given Scala's type erasure, how can I iterate through it without casting:
@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
is invariant in T
so there should be way to accomplish this?
You can try defining extractors:
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)
}
You may have to give them another name if you can't put them in the same files as where the original traits are defined.
On another point, the implementation of your lastValue
function probably doesn't do what you expect… How about this one instead?
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)
}