1. 概要

このチュートリアルでは、Scalaの暗黙的なパラメーターとその使用方法を見ていきます。

2. 暗黙のパラメータとは何ですか?

暗黙的なパラメータは通常のメソッドパラメータに似ていますが、通常のパラメータリストを経由せずにサイレントにメソッドに渡すことができる点が異なります。

メソッドは、通常のパラメーターのリストの後に配置される暗黙的なパラメーターのリストを定義できます。 これらのパラメーターはimplicitキーワードを使用して示され、implicitキーワードの後のすべてのパラメーターは暗黙的です。

def draw(text: String)(implicit color: Color, by: DrawingDevice)

3. 使用法

メソッドが暗黙的パラメーターで定義されている場合、Scalaは、暗黙的パラメーター・リストにまだ渡されていない場合、type と照合することにより、スコープ内の暗黙的値を検索します。

ColorDrawingDeviceの2つのケースクラスが定義されているとします。

case class Color(value: String)
case class DrawingDevice(value: String)

次に、 String を通常のパラメーターとして受け取り、2つのケースクラスを暗黙のパラメーターとして受け取るwriteメソッドを定義しましょう。

def write(text: String)(implicit color: Color, by: DrawingDevice) =
  s"""Writing "$text" in ${color.value} color by ${by.value}."""

ColorおよびDrawingDeviceインスタンスをwriteメソッドに提供するには、インスタンスを暗黙として定義し、メソッドを呼び出します。

implicit val red: Color = Color("red")
implicit val drawingDevice: DrawingDevice = DrawingDevice("pen")
assert(
    write("A good day") ==
      """Writing "A good day" in red color by pen."""
  )

Scalaが暗黙の値と一致する場合、パラメーター名と変数名は無視されます。 前述のように、Scalaはタイプごとに暗黙の値と一致します。

複数の暗黙の変数が同じタイプを共有する場合はどうなりますか? writeByMixColors メソッドを変更して、これを調べます。

def writeByMixColors(text: String)(implicit color: Color, color2: Color, by: DrawingDevice) = 
  s"""Writing "$text" in ${color.value} and ${color2.value} colors by ${by.value}."""

この場合、2つの暗黙的なパラメーターがあります( color2 )両方のタイプ色。 Scalaは値と一致しますパラメータリストの各色に。 その結果、出力は次のようになります。

Writing "A good day" in red and red colors by pen.

ただし、2つの異なる暗黙の Color値を定義するとどうなりますか?

implicit val red: Color = Color("red")
implicit val green: Color = Color("green")
implicit val pen: DrawingDevice = DrawingDevice("pen")

println(writeByMixColors("A good day")) // This won't compile.

これにより、あいまいな暗黙の値のエラーメッセージが表示されます。 redgreenはどちらもColorですが、Scalaはどちらがパラメーターと一致するかわかりません。

ただし、暗黙的な値を非暗黙的な方法で渡すことができます

implicit val red: Color = Color("red")
implicit val green: Color = Color("green")
implicit val pen: DrawingDevice = DrawingDevice("pen")

println(writeByMixColors("A good day")(red, green, pen))

結果は次のようになります。

Writing "A good day" in red and green colors by pen.

この場合、暗黙のパラメーターは通常のパラメーターのように機能します。 ただし、これを行う場合、デフォルト値が指定されていない限り、暗黙的パラメーターのリスト全体を渡す必要があります。

最後に、 writeByMixColors メソッドを呼び出し、暗黙のパラメーターを定義していない場合、コンパイラーは暗黙の値が見つからなかったことを通知するエラーを返します。

4. 利点

暗黙のパラメーターを適切に使用すると、読みやすさと再利用性が向上する可能性があります。 これにより、スコープ内にある限り、コード内の任意の場所で値を定義できます。 さらに、暗黙のパラメーターを探す他のメソッド間で再利用できます。

implicit val red: Color = Color("red")
implicit val pen: DrawingDevice = DrawingDevice("pen")

assert(
  write("A good day") ==
    """Writing "A good day" in red color by pen."""
)
assert(
  write("Drink a cup of coffee") ==
    """Writing "Drink a cup of coffee" in red color by pen."""
)
assert(
  write("Write some code") ==
    """Writing "Write some code" in red color by pen."""
)

実際の例は、データベースの create read update、、および delete (CRUD)操作です。

// without implicit parameter
model.create(conn, newRecord)

// with implicit parameter
model.create(newRecord)

これらの操作の重要な部分はレコード自体ですが、多くの場合、コードと一緒にデータベース接続を実行する必要があります。 そのため、データベース接続はCRUD操作の暗黙的なパラメーターの候補として適しています。

5. 短所

暗黙的なパラメーターはコード設計の改善に役立ちますが、それを使いすぎるとコードの可読性に悪影響を与える可能性があります。 通常のパラメータよりも目立たない場合があります。 コードレビューアは、コードを完全に理解するために、より多くの注意を払わなければならないことがよくあります。

Apache Flinkプロジェクトでは、コードを推論しやすくするために、これらのパラメーターから離れることを推奨しています

6. 結論

この記事では、暗黙のパラメーターとその使用方法について説明しました。

これらはクリーンなコードを設計するのに非常に役立ちますが、同時に、それらを使いすぎると読みやすさの問題が発生する可能性があることに注意する必要があります。

いつものように、コード例はGitHubにあります。