sbt でmainメソッドを実行する方法
sbt でクラスパスにあるクラスのmainメソッドを実行する方法
sbt "run-main com.example.Main arg1 arg2"
たぶんrun-mainに限らずなのですが、sbt 以下の引数をごっそり"で囲むのがポイント
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[_]の方法を採用しました。いろいろ勉強になります。
遅延評価させるには
Query.listじゃなくて、Query.elements で CloseableIteratorを取得しましょう、と。
ローカルリポジトリのパスは変わってなかった。
maven3 だとローカルリポジトリのパスが変わっていますね。 - ayakobabaの日記 って昨日書いたけど、嘘でした!!
会社のCIサーバの設定は、権限もろもろがないのでみれないのですが、ローカルPCにインストールされているmaven3の設定をみたけど、ローカルリポジトリのぱす変わってないし、setting.xmlにも
<!-- localRepository | The path to the local repository maven will use to store artifacts. | | Default: ~/.m2/repository
って書いてありました。信じてくれたひとごめんなさい。でも私的には川口さんと言葉を交わせたからいいやー。いやしかし驚いたよ。
maven3 だとローカルリポジトリのパスが変わっていますね。
jenkins(hudson)サーバとmaven の社内リポジトリを一緒にするといいことがある、きっと。 - ayakobabaの日記 で書いたように、会社ではCIサーバのユーザのローカルリポジトリを、社内のリポジトリとして公開しています。
で、今日みたらmaven3がJenkinsさんで使えるようになっていたので、maven3でビルドしてみました!が、社内リポジトリへ公開はされず。なんでだろうと思ったら、maven2では、ローカルリポジトリはデフォルトで $HOME/.m2/repository だったのが、 maven3 では$HOME/.maven/repo に変わってますね。
たいしたことではないですが、リモートのリポジトリをみないような設定を実施してた場合、maven3に変えると「ライブラリがない!」といってはまるかも。。(あんまりそういう人はいなさそうですが)。それだけです。
foldLeftとmutableMap
最近Scalaにちょーーっとだけ慣れてきたので、なんとなくvarやmutableな何かをつかったら負けた気分になってしまいます。何かを集計してMapを作る、みたいな処理も嬉々としてfoldLeftつかってやってたら、社内のコードレビューで「インスタンス生成爆発で遅くなるからmutable.Map使った方がよくない?」って。
そ、そんなことないんじゃないのかなあ(動揺)。というわけで調べた。
コード。
val list = List.range(0, 100000) for (time <- 1 to 10) { val startTime = System.currentTimeMillis() val map = list.foldLeft(Map[Int, String]()) { (m, i) => m + (i -> ("value" + i)) } println("foldLeft time: " + (System.currentTimeMillis() - startTime)) } for (time <- 1 to 10) { val startTime = System.currentTimeMillis() val map2 = collection.mutable.Map[Int, String]() for (i <- list) { map2.put(i, "value" + i) } println("mutable time:" + (System.currentTimeMillis() - startTime)) }
結果
foldLeft time: 415 foldLeft time: 137 foldLeft time: 147 foldLeft time: 146 foldLeft time: 154 foldLeft time: 152 foldLeft time: 136 foldLeft time: 136 foldLeft time: 128 foldLeft time: 127 mutable time:137 mutable time:96 mutable time:124 mutable time:84 mutable time:110 mutable time:110 mutable time:85 mutable time:104 mutable time:106 mutable time:107
。。。そりゃそうですよね。
正直、思ったよりfoldLeftは善戦してた。
これから書き直します。