概要
classのコンストラクタ関数の最初の引数グループをimplicitなアレにしたらどうなるんだろう、と思ったので遊んでみた。
case class
試したログ
$ scala
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_67).
Type in expressions to have them evaluated.
Type :help for more information.
scala> case class Hoge(implicit a:String)
defined class Hoge
scala> Hoge
res0: Hoge.type = Hoge ### `Hoge`だとコンストラクタではなくオブジェクトとして認識される
scala> Hoge("str") ### 直接指定してみる
<console>:10: error: too many arguments for method apply: ()(implicit a: String)Hoge in object Hoge
Hoge("str") ### ↑コンストラクタのシグネチャがapply()(implicit a: String)になってる
^
scala> Hoge()("str") ### 試しにそのとおりにやってみる。
res2: Hoge = Hoge(str) ### 動いた
scala> implicit val a = "implicit string" ### implicit parameterを定義してやってみる
a: String = implicit string
scala> Hoge()
res3: Hoge = Hoge(implicit string) ### 動いた
結果
case classのコンストラクタの最初の引数グループをimplicitにすると、勝手にcurry化されて2つ目の引数グループになる。
こういう場合、pattern matchってどうなるんだろう?と思って調べてみたら、implicitとか関係なくcurry化されたcase classは自動でunapply
を実装してくれないらしい(=そのままではpattern matchで使えない)
自前でunapplyを実装すれば使える模様。
caseじゃないclass
試したログ
$ scala
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_67).
Type in expressions to have them evaluated.
Type :help for more information.
scala> class Hoge(implicit val a:String)
defined class Hoge
scala> new Hoge
<console>:9: error: could not find implicit value for parameter a: String
new Hoge
^
### implicit定義してないので当たり前
scala> new Hoge("str") ### 直接指定してみる
<console>:9: error: too many arguments for constructor Hoge: ()(implicit a: String)Hoge
new Hoge("str") ↑case classと同じく勝手にcurry化されてる
^
scala> new Hoge()("str") ### 2つめの引数グループに直接指定。
res2: Hoge = Hoge@194527c6 ### 動いた。
scala> res2.a
res3: String = str ### ちゃんと中身もある
scala> implicit val a = "implicit string" ### implicit定義して試してみる
a: String = implicit string
scala> new Hoge()
res4: Hoge = Hoge@6963eb77 ### 普通に動く
scala> new Hoge
res5: Hoge = Hoge@78924119 ### もはや1つめのカッコも省略できる
結果
case classと同じ。
感想
勝手にcurry化されるのはびびった。ただ、こういうのは豆知識として知っておくのはいいけど、それを気にしないようなコードを書くように心がけよう。
あとimplicit云々関係なくコンストラクタがcurry化されてるとcase classでもパターンマッチが(自前でunapplyを書かない限り)使えず、case classの旨味がかなり減っちゃう。仮に自前でunapply書いたとしても、パターンマッチの書き方が混乱しそう。
あとcurry化した時の引数のカッコが分かれるやつを、「引数グループ」って表現したけど、それ専用の用語ってあるのかな。