Implicit Parameter は暗黙の引数だ。2つの使い方があるようだけど、今日はその1つ、あちこちで共通に使われる引数を、いちいち明示的に渡すのを省略するための使い方を見ていこう。
参考にしている Dwango の研修資料では、データベースのコネクションの例が示されているけど、ここではもっと簡単な例を示す。
scala> def add(x: Int)(implicit y: Int): Int = x + y add: (x: Int)(implicit y: Int)Int scala> def sub(x: Int)(implicit y: Int): Int = x - y sub: (x: Int)(implicit y: Int)Int scala> def mul(x: Int)(implicit y: Int): Int = x * y mul: (x: Int)(implicit y: Int)Int
Implicit Parameter を使うには、引数宣言に implicit キーワードをつけるだけだ。ただし、implicit キーワードをつけられるのは引数リストの最初に引数だけ、という制約があるので、通常は複数の引数リストを持つメソッドにして最後に Implicit Parameter を持ってくるようだ。
さて、これらのメソッドを呼び出すと、Scala は現在のスコープで直近にある implicit とマークされた変数の値を、Implicit Parameter としてメソッドに引き渡す。具体的には次のようにする。
scala> implicit val z: Int = 2 z: Int = 2 scala> add(3) res0: Int = 5 scala> sub(3) res1: Int = 1 scala> mul(3) res2: Int = 6
implicit val で宣言された変数 z が、メソッド呼び出しの時に暗黙に引き渡されている。
ここで、新しい変数を implicit で宣言したらどうなるだろう。
scala> implicit val z1: Int = 5 z1: Int = 5 scala> add(3) <console>:15: error: ambiguous implicit values: both value z of type => Int and value z1 of type => Int match expected type Int add(3) ^
おや、エラーになった。どうやら、期待する Implicit Parameter にマッチする値が2つあるせいのようだ。こういう使い方はできないらしい。
明示的に渡してやったらどうだろう。
scala> add(3)(z1) res4: Int = 8
ああ、これは普通にいけるのね。
というかさあ、こういうあちこちで使いまわす変数っていうのは、オブジェクト指向的にはオブジェクトのメンバー変数にしておくんだろうけど、Scala では違うんだろうか。