型パラメーターを使った Array.fill とかをしたい場合

環境

scala 2.9.1.final

まずは REPL でやってみる

scala> def fill[T](v: T) = List.fill(10)(v)
fill: [T](v: T)List[T]

scala> fill("hoge")
res0: List[java.lang.String] = List(hoge, hoge, hoge, hoge, hoge, hoge, hoge, hoge, hoge, hoge)

scala> def fill[T](v: T) = Array.fill(10)(v)
<console>:7: error: could not find implicit value for evidence parameter of type scala.reflect.ClassManifest[T]
       def fill[T](v: T) = Array.fill(10)(v)

????????????


なんぞこれwww
List.fill は動くのに Array.fill は動きません!!!!

List.fill と Array.fill は引数が違うらしい

http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.List$
http://www.scala-lang.org/api/current/index.html#scala.Array$


ドキュメントみりゃ分かるんですが


List は fill [A] (n: Int)(elem: ⇒ A): List[A] となってるのに対して
Array は fill [T] (n: Int)(elem: ⇒ T)(implicit arg0: ClassManifest[T]): Array[T] になってるっぽいです。


なんでこうなってるのかは知りませんが、こうなってるから動かないのは分かりました。


というわけで ClassManifest (型情報的なもの)を渡してあげましょう。
ClassManifest 結構大事だと思ってるので、くどいですが最初は一つずつやってみます。


またまた手前味噌でさーせんが ClassManifest の基本的な部分はこちらをどうぞorz
http://wiki.livedoor.jp/alphaneet/d/scala%3a%3a%b7%bf%a5%d1%a5%e9%a5%e1%a1%bc%a5%bf%a1%bc

1: ClassManifest を手渡しでやってみる

引き続き REPL で

scala> def fill[T](v: T, cm: ClassManifest[T]) = Array.fill(10)(v)(cm)
fill: [T](v: T, cm: ClassManifest[T])Array[T]

scala> fill(12345, classManifest[Int])
res4: Array[Int] = Array(12345, 12345, 12345, 12345, 12345, 12345, 12345, 12345, 12345, 12345)

出来ました。でも、もの凄い冗長ですよね。

2: implicit を使って省略してみる。

scala> def fill[T](v: T)(implicit cm: ClassManifest[T]) = Array.fill(10)(v)(cm)
fill: [T](v: T)(implicit cm: ClassManifest[T])Array[T]

scala> fill("moke")
res5: Array[java.lang.String] = Array(moke, moke, moke, moke, moke, moke, moke, moke, moke, moke)

呼び出し方がすっきりしました。
ちなみに Array.fill(10)(v)(cm) のところは Array.fill(10)(v) でも動きます。


実はまださらに省略することが出来ます。

3: context bound を使ってみる

scala> def fill[T: ClassManifest](v: T) = Array.fill(10)(v)
fill: [T](v: T)(implicit evidence$1: ClassManifest[T])Array[T]

scala> fill("oppai")
res6: Array[java.lang.String] = Array(oppai, oppai, oppai, oppai, oppai, oppai, oppai, oppai, oppai, oppai)

凄いすっきりしましたね。

まとめ

1、2、3 はそれぞれやってること自体は大体一緒です。


今回は Array(標準API) なんでどの方法使ってもいいと思いますが、自分でライブラリ作った場合どの方法で実装するのがいいのかなーと考えますと。。。


1 は論外として 2 と 3 どっちを選ぶか悩みますね。
3 は確かにすっきりしててイケメンなんですが、省略しすぎて他の人が見た時混乱するかもしれません。


個人(趣味)開発の場合はどっちでもいいと思いますが(むしろ 3 カコイイ)
チーム開発の場合は 2 ぐらいで妥協しておくべきかなーと思いました。まる。