LoginSignup
2
2

More than 5 years have passed since last update.

classのコンストラクタの最初の引数グループがimplicitだった時の挙動

Posted at

概要

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化した時の引数のカッコが分かれるやつを、「引数グループ」って表現したけど、それ専用の用語ってあるのかな。

2
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2