Deletions are marked like this. | Additions are marked like this. |
Line 61: | Line 61: |
つまり、 | つまり、以下のように記述して、valueの値を指定できないものだろうか。 |
Line 63: | Line 63: |
implicit def toBeImplicitArg: Sample = new Sample(...ここを自由に変更できないものか...) | implicit def toBeImplicitArg(value: Int): Sample = new Sample(value) |
Line 65: | Line 65: |
ところが、これは一般に不可能のようである(たぶん)。ただし、[[http://www.scala-lang.org/node/114|A Tour of Scala: Implicit Parameters]]を見てみると、型パラメータの値によって引数値を選択することはできるようだ。この例をもう少し単純化してみる。 {{{ abstract class Add[A] { def add(x: A, y: A): A } object ImplicitTest { implicit object AddString extends Add[String] { def add(x: String, y: String) = x + y } implicit object AddInt extends Add[Int] { def add(x: Int, y: Int) = x + y } def sum[A](a: A, b: A)(implicit m: Add[A]) = m.add(a, b) def main(args: Array[String]) { println(sum(1, 2)) println(sum("a", "b")) } } }}} この結果は、 {{{ 3 ab }}} つまり、型パラメータによってString型を処理するAddStringか、Int型のAddIntが自動選択される。 |
implicit
暗黙のパラメータ
implicitとマークされた引数は、その型と一致し、implicitとマークされたオブジェクトが存在すれば自動的に供給される。
object ImplicitTest { class Sample(value: Int) { override def toString = { "Sample:" + value } } // 暗黙的に供給されるオブジェクト。implicitを記述する implicit val toBeImplicitArg = new Sample(1); // implicitとマークされた引数を持つメソッド。implicitを記述する。 def methodWithImplicitArg(implicit s: Sample) { println("methodWithImplicitArg called:" + s) } def main(args: Array[String]) { methodWithImplicitArg // 暗黙的に供給 methodWithImplicitArg(new Sample(2)) // 明示的に供給 // methodWithImplicitArg() ... この場合、()をつけてはだめ。引数が不足と言われてしまう。 } }
この結果は
methodWithImplicitArg called:Sample:1 methodWithImplicitArg called:Sample:2
供給側を関数に変更
上記の
implicit val toBeImplicitArg = new Sample(1);
は、関数に変更しても機能する。
implicit def toBeImplicitArg: Sample = new Sample(1)
供給側をオブジェクトに変更
供給側をオブジェクトに変更してもよい。
implicit object toBeImplicitArg extends Sample(1) {}
つまり、implicitとマークされた引数に供給できるものは、implicitのvalに限ることなく、implicitのdefやimplicitのobjectでもよい。
その場に応じた引数値を生成する方法
上記の関数を使った場合の例では、固定的な値だけではなく、その場で値を作成することもできそうだが、 このままでは同じ値「new Sample(1)」しか作成されない。 呼び出される「文脈」をtoBeImplicitArg関数に与え、その場に応じた値を作成できないとまったく面白くはない。 つまり、以下のように記述して、valueの値を指定できないものだろうか。
implicit def toBeImplicitArg(value: Int): Sample = new Sample(value)
ところが、これは一般に不可能のようである(たぶん)。ただし、A Tour of Scala: Implicit Parametersを見てみると、型パラメータの値によって引数値を選択することはできるようだ。この例をもう少し単純化してみる。
abstract class Add[A] { def add(x: A, y: A): A } object ImplicitTest { implicit object AddString extends Add[String] { def add(x: String, y: String) = x + y } implicit object AddInt extends Add[Int] { def add(x: Int, y: Int) = x + y } def sum[A](a: A, b: A)(implicit m: Add[A]) = m.add(a, b) def main(args: Array[String]) { println(sum(1, 2)) println(sum("a", "b")) } }
この結果は、
3 ab