1. 概要

このチュートリアルでは、暗黙の変換について学習します。 それらがボイラープレートコードをどのように削減し、既存のクラスにメソッドを追加するためにどのように使用できるかを見ていきます。

2. 暗黙の変換

暗黙の変換により、Scalaコンパイラーはあるタイプを別のタイプに変換することができます

それらを使用して、既存のクラスにメソッドを追加することもできます。 ただし、Scala 2.10以降、このユースケースでは暗黙のクラスを使用する必要があります。

3. 長さのユースケース

長さの単位を表すさまざまなタイプがあると想像してみましょう。

case class Centimeters(value: Double) extends AnyVal
case class Meters(value: Double) extends AnyVal
case class Kilometers(value: Double) extends AnyVal

ボイラープレートコードなしで互換的に使用したいと思います。

4. 暗黙の変換方法

使いたいならメートルある場所でセンチメートルが必要な場合は、からの暗黙的な変換を提供する必要がありますメートルの中へセンチメートル。 暗黙のメソッドを作成することでそれを行うことができます。 メートルと戻りますセンチメートル

implicit def meters2centimeters(meters: Meters): Centimeters =
  Centimeters(meters.value * 100)

val centimeters: Centimeters = Meters(2.5)

centimeters shouldBe Centimeters(250)

Scalaコンパイラは、 MetersCentimetersのサブタイプではないことを認識しています。ただし、コンパイルエラーの代わりに、Metersを変換する暗黙の変換が利用可能かどうかをチェックします。 ]センチメートルに。

したがって、暗黙の Meters2centimeters メソッドを提供し、 Meters(2.5)をタイプCentimeters。の可変センチメートルに割り当てることができます。

5. 暗黙の変換関数

陰関数は、陰変換を提供する別の方法です。

implicit val kilometers2meters: Kilometers => Meters =
  kilometers => Meters(kilometers.value * 1000)

val meters: Meters = Kilometers(2.5)

meters shouldBe Meters(2500)

今回は、暗黙のキロメートル2メートル関数を提供し、キロメートルメートルとして扱うことができるようになりました。

6. 拡張メソッド

暗黙的な変換を使用して、既存のクラスにメソッドを追加することもできます。 それでは、長さの単位を作成するためのセンチメートル、メートル、およびキロメートルメソッドをDoubleに追加しましょう。

class LengthSyntax(value: Double) {
  def centimeters = Centimeters(value)
  def meters = Meters(value)
  def kilometers = Kilometers(value)
}

implicit def double2richSyntax(value: Double): LengthSyntax =
  new LengthSyntax(value)

val length: Double = 2.5

length.centimeters shouldBe Centimeters(length)
length.meters shouldBe Meters(length)
length.kilometers shouldBe Kilometers(length)

この場合、コンパイラは、Doubleをセンチメートル、メートル、またはキロメートルのメソッドを持つものに変換する暗黙の変換を探しています。 したがって、暗黙の double2richSyntax メソッドを提供し、コンパイラーは何をすべきかを知っています。

7. 制限事項

残念ながら、暗黙の変換にはいくつかの制限があります。

  • 複数の非暗黙的な引数を取ることはできません
  • 複数の暗黙的な変換を連鎖させることはできません

7.1. 非暗黙の引数

複数の非暗黙的な引数を取ることはできません。

implicit def meters2centimeters(meters: Meters, secondArg: Boolean): Centimeters =
  Centimeters(meters.value * 100)

val centimeters: Centimeters = Meters(2.5)

2番目の非暗黙的な引数を追加したため、上記のコードはコンパイルされません。 コンパイラは、メートルセンチメートル:として扱うことができません。

[error] type mismatch;
[error] found : com.baeldung.scala.implicitconversions.Meters
[error] required: com.baeldung.scala.implicitconversions.Centimeters
[error] val centimeters: Centimeters = Meters(2.5)

ただし、追加の暗黙の引数があることは問題ではありません。

implicit val boolean = true
implicit def meters2centimeters(meters: Meters)(implicit secondArg: Boolean): Centimeters =
  Centimeters(meters.value * 100)

val centimeters: Centimeters = Meters(2.5)

7.2. チェーンの暗黙的な変換

複数の暗黙的な変換を連鎖させることはできません。

implicit def kilometers2meters(kilometers: Kilometers): Meters =
  Meters(kilometers.value * 1000)
implicit def meters2centimeters(meters: Meters): Centimeters =
  Centimeters(meters.value * 100)

val centimeters: Centimeters = Kilometers(2.5)

Scalaコンパイラーは、1つの暗黙的な変換のみを考慮に入れることができます。 したがって、キロメートルセンチメートルタイプのセンチメートル変数に割り当てることはできません。

[error] type mismatch;
[error] found : com.baeldung.scala.implicitconversions.Kilometers
[error] required: com.baeldung.scala.implicitconversions.Centimeters
[error] val centimeters: Centimeters = Kilometers(2.5)

ただし、キロメートルからメートルおよびメートルからセンチメートルへの暗黙の変換を行うことができます。

8. 警告

私たちが見たように、暗黙の変換には大きな力があります。 それにもかかわらず、大きな力には大きな責任が伴います。 したがって、Scalaコンパイラーは、暗黙的な変換の使用について常に警告します。

[warn] implicit conversion method meters2centimeters should be enabled

build.sbt でコンパイラオプションを設定することにより、プロジェクト全体で暗黙的な変換を有効にできます。

scalacOptions += "-language:implicitConversions"

一方、特定のクラスまたはメソッドに対してのみ有効にする場合は、単一のインポートを使用して有効にすることができます。

import scala.language.implicitConversions

9. 結論

この短い記事では、暗黙の変換について説明しました 。 ボイラープレートコードを削減する方法と、既存のクラスにメソッドを追加するために使用する方法を確認しました。

いつものように、記事の完全なソースコードは、GitHubから入手できます。