case文で型パラメータをつかうとき
Scala でこんなプログラムを書いたとします。
tuple match{ case t:(Int,String) => println("(Int,String) tuple") case _ => println("Not a (Int,String) tuple!") }
これ、コンパイル通ります。ただし、例えば、(String,String)のtuple を渡した場合、2行めのt:(Int,String)にマッチしてしまいます。というのは、バイトコードに変換されてしまうと、tの2要素のタプルであることは判断できるものの、tの各要素の型まではわからなくなってしまうからです。
もう少し詳しくみると、型指定の
(Int,String)
の部分は、
Tuple2[Int,String]
というように、Tuple2に型パラメータを指定しているのと同じことですが、この型パラメータの[Int,String]の情報がバイトコードになるとごっそり抜け落ちます。Scalaの型パラメータはJavaのジェネリクスに変換されるのですが、Javaはバイトコードの下位互換性を保つためにバイトコード生成時にジェネリクス情報をすべて消し込むerasureモデルを採用するからです。だから、tはTuple2かどうかはわかるけど、Tuple2[Int,String]かはわからない。
同じ理由で以下のコードも「Stringの」Listかどうかは、みてません(みれないから)
list match{ case l:List[String] => "This is String List!" case _ => "This is not a String List!!" }
なんでこんなことが気になったかというと、このようなコードがScalaDoc生成時にwarningをいっぱいだしたから。warningを出さない方法は、2種類あります。まず、「「Stringの」Listかどうかなんてそんなに気にしないよ。」という場合。このような場合は、
list match{ case l:List[_] => "This is a List!" case _ => "This is not a List!" }
と、型パラメータの部分を _ にすればよいです。caseのあとの処理のブロックでListの要素に対してString型のメソッドを実行したい場合も、asInstanceOf を利用してキャストすればいけます。(なんとなくちょっと不細工ですが)
問題は、「Stringの」Listだ、ということを検証したい場合です。以下のページでも議論されていますが、ちょっと工夫しないと難しそうです。
Listの場合は、
などなどの方法が考えられます。Tupleなどは、2番目の「クラスを作る」という方法をとった方がコードがすっきりしそうな気がします。
今回は文脈上問題なかったので、List[_]の方法を採用しました。いろいろ勉強になります。