Tour of Scala

暗黙のパラメータ

Language

メソッドは 暗黙の パラメータのリストを持つことができ、パラメータリストの先頭には implicit キーワードで印をつけます。 もしそのパラメータリストの中のパラメータがいつものように渡らなければ、Scalaは正しい型の暗黙値を受け取ることができるかを確認し、可能であればそれを自動的に渡します。

Scalaがこれらのパラメータを探す場所は2つのカテゴリに分かれます。

  • Scalaはまず最初に暗黙のパラメータブロックを持つメソッドが呼び出されている箇所で、直接(プレフィックスなしに)アクセスできる暗黙の定義と暗黙のパラメータを探します。
  • 次に、候補となる型に関連づけられた全てのコンパニオンオブジェクトの中でimplicitと宣言されているメンバーを探します。

Scalaがimplicitをどこから見つけるかについてのより詳しいガイドはFAQで見ることができます。

以下の例では、モノイドのaddunitの演算を使い、要素のリストの合計を計算するメソッドsumを定義しています。 implicitの値をトップレベルには置けないことに注意してください。

abstract class Monoid[A] {
  def add(x: A, y: A): A
  def unit: A
}

object ImplicitTest {
  implicit val stringMonoid: Monoid[String] = new Monoid[String] {
    def add(x: String, y: String): String = x concat y
    def unit: String = ""
  }
  
  implicit val intMonoid: Monoid[Int] = new Monoid[Int] {
    def add(x: Int, y: Int): Int = x + y
    def unit: Int = 0
  }
  
  def sum[A](xs: List[A])(implicit m: Monoid[A]): A =
    if (xs.isEmpty) m.unit
    else m.add(xs.head, sum(xs.tail))
    
  def main(args: Array[String]): Unit = {
    println(sum(List(1, 2, 3)))       // intMonoidを暗に使用
    println(sum(List("a", "b", "c"))) // stringMonoidを暗に使用
  }
}

Monoidはここではaddと呼ばれる処理を定義します。この処理はAのペアを結合して、別のAを返します。また、(特定の)Aを作ることができるunitと呼ばれる処理も定義します。

暗黙のパラメータがどのように働くかを見るため、まずは文字列と整数のためにそれぞれモノイドstringMonoidintMonoidを定義します。implicitキーワードは対応するオブジェクトが暗黙に使われうることを指し示します。

メソッドsumList[A]を受け取り、Aを返します。このメソッドは初期値Aunitから受け取り、リスト中のAを順番にaddメソッドで結合します。ここでパラメータmをimplicitにしているのは、そのメソッドを呼び出すとき、Scalaが暗黙のパラメータmとして暗黙のMonoid[A]を見つけることができるなら、私達はxsパラメータを提供するだけで良いということです。

mainメソッドではsumを2回呼んでいて、xsパラメータだけを渡しています。するとScalaは先に言及したスコープの中でimplicitを探します。最初のsumの呼び出しはxsとしてList[Int]を渡します。それは AIntであることを意味します。暗黙のパラメータリストmが省略されているので、Scalaは暗黙のMonoid[Int]を探します。最初の探索ルールはこうでした。

Scalaはまず最初に暗黙のパラメータブロックを持つメソッドが呼び出されている箇所で、直接(プレフィックスなしに)アクセスできる暗黙の定義と暗黙のパラメータを探します。

intMonoidmainの中で直接アクセスできる暗黙の定義です。型も一致しているので、sumメソッドに自動的に渡されます。

sumの2回目の呼び出しはList[String]を渡します。それはAStringであることを意味します。暗黙の値の探索はIntの時と同様に動きますが、今回は stringMonoidを見つけ、mとして自動的に渡します。

そのプログラムは以下を出力します。

6
abc

Contributors to this page: