2011-07-23 27 views
1

给出一个假设的可变链表(假设这是一个给定的结构 - 所以没有要改变它的建议,请):避免类型转换的模式匹配

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所以应该有办法做到这一点?

回答

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

嗯,还不错。是的,我可以让他们在原始文件中,这不是问题。 (当然,对于前一个值的正确跟踪,你是对的)。我认为必须有一个提取模式,但无法弄清楚。 –

+0

看我们在选择头部还是尾部时,我们意外不需要在'case c:CCons [_]'后面投射。也许编译器认为'c'与CCons [_]'是一样的'CList [T],它明确地解析为'CCons [T]'?... –