2011-07-23 10 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! 
} 

CListTで不変であるので、これを実現するための方法があるはず?

答えて

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関数の実装は、おそらくあなたが期待したことをしないでしょう...代わりに、この1つについてはどうですか?

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

Hmmm、悪くない。はい、元のファイルに入れても問題ありません。 (そして、あなたはもちろん、以前の値の適切な追跡について)。私は抽出パターンがなければならないと思ったが、それを理解できなかった。 –

+0

頭や尾を選択したときに 'case c:CCons [_]'の後にキャストする必要がないことを見てください。たぶん、コンパイラは 'c'を 'CCons [T]'に解決する '' CCist [_] 'と' 'CList [T] ''のように考えるでしょうか? –