1. 概要

このチュートリアルでは、暗黙のクラスについて学習します。 それらの属性、制限、および既存のクラスにメソッドを追加するためにそれらを使用する方法について学習します。

2. 暗黙のクラス

暗黙のクラスはScala2.10以降で利用可能であり、既存のクラスにメソッドを追加する機能を提供します。 そのおかげで、IntString。などの組み込みクラスにいくつかの便利なメソッドを簡単に追加できます。

3. お金のユースケース

金額と通貨を含むMoneyケースクラスがあると想像してみましょう。

sealed trait Currency
object Currency {
  case object EUR extends Currency
  case object USD extends Currency
  case object GBP extends Currency
}

case class Money(amount: Double, currency: Currency)

次の構文を使用してMoneyを作成する便利な方法が必要です。

val amount: Double = 30.5

val euros: Money = amount.euros
val dollars: Money = amount.dollars
val pounds: Money = amount.pounds

4. お金の構文の作成

これを実現するには、ユーロドル、およびポンドメソッドをDoubleクラスに追加する暗黙のクラスを提供する必要があります。

object MoneySyntax {
  implicit class RichMoney(val amount: Double) extends AnyVal {
    def euros: Money = Money(amount, Currency.EUR)
    def dollars: Money = Money(amount, Currency.USD)
    def pounds: Money = Money(amount, Currency.GBP)
  }
}

上記の例では、任意のDouble にユーロ、ドル、ポンドのメソッドを追加するRichMoneyという暗黙のクラスを作成しました。 また、 AnyVal を拡張して、実行時の割り当てを回避します。

5. Money構文の使用

暗黙のクラスを作成したので、それを使用して、新しい構文が機能するかどうかを確認します。

import MoneySyntax._

val amount: Double = 30.5
  
amount.dollars shouldBe Money(amount, Currency.USD)
amount.euros shouldBe Money(amount, Currency.EUR)
amount.pounds shouldBe Money(amount, Currency.GBP)

まず、 import MoneySyntax ._ を使用して、暗黙のクラスRichMoneyをスコープで使用できるようにする必要があります。

コンパイラは、 Double で使用可能なドルメソッドがないことを認識しているため、ドルメソッドをDoubleに追加する使用可能な暗黙のクラスを見つけようとします。 。インポートのおかげで、 RichMoney がスコープで使用可能になり、コンパイラーが満足できるようになります。

同様に、ユーロおよびポンドメソッドでも同じことが起こります。

6. 制限事項

残念ながら、すべてのクラスが暗黙のクラスになるわけではありません。

  • トップレベルのオブジェクトとして定義することはできません
  • コンストラクターで複数の非暗黙的な引数を取ることはできません
  • ケースクラスで暗黙のクラスを使用することはできません
  • スコープ内に暗黙のクラスと同じ名前のメンバーまたはオブジェクトを含めることはできません

6.1. トップレベルオブジェクト

トップレベルのオブジェクトとして定義することはできません。

implicit class RichMoney(amount: Double) {
  def euros: Money = Money(amount, Currency.EUR)
  def dollars: Money = Money(amount, Currency.USD)
  def pounds: Money = Money(amount, Currency.GBP)
}

これはコンパイルされません。理由は次のとおりです。‘implicit’修飾子はトップレベルオブジェクトには使用できません

したがって、 RichMoney トレイト、クラスオブジェクト、またはパッケージオブジェクトに移動する必要があります。

trait MoneySyntax {
  implicit class RichMoney(amount: Double) {
    def euros: Money = Money(amount, Currency.EUR)
    def dollars: Money = Money(amount, Currency.USD)
    def pounds: Money = Money(amount, Currency.GBP)
  }
}

AnyValを拡張してRichMoneyの割り当てを回避したい場合は、オブジェクトパッケージオブジェクトのみに制限されます。 X162X]valueクラスは別のクラス’のメンバーではない可能性があります。

object MoneySyntax {
  implicit class RichMoney(val amount: Double) extends AnyVal {
    def euros: Money = Money(amount, Currency.EUR)
    def dollars: Money = Money(amount, Currency.USD)
    def pounds: Money = Money(amount, Currency.GBP)
  }
}

6.2. 非暗黙の引数

コンストラクターで複数の非暗黙の引数を取ることはできません。

object MoneySyntax {
  implicit class RichMoney(amount: Double, secondArg: Boolean) {
    def euros: Money = Money(amount, Currency.EUR)
    def dollars: Money = Money(amount, Currency.USD)
    def pounds: Money = Money(amount, Currency.GBP)
  }
}

上記のコードはコンパイルされません。これは、「暗黙のクラスには、最初のパラメーターリストに引数が1つだけあるプライマリコンストラクターが必要である」ためです。

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

object MoneySyntax {
  implicit class RichMoney(amount: Double)(implicit secondArg: Boolean) {
    def euros: Money = Money(amount, Currency.EUR)
    def dollars: Money = Money(amount, Currency.USD)
    def pounds: Money = Money(amount, Currency.GBP)
  }
}

6.3. ケースクラス

ケースクラスで暗黙のクラスを使用することはできません。

object MoneySyntax {
  implicit case class RichMoney(amount: Double) {
    def euros: Money = Money(amount, Currency.EUR)
    def dollars: Money = Money(amount, Currency.USD)
    def pounds: Money = Money(amount, Currency.GBP)
  }
}

コンパイラは次のメッセージで失敗します:’修飾子の不正な組み合わせ:暗黙的および大文字と小文字:クラスRichMoney’。

6.4. 範囲

スコープ内に、暗黙のクラスと同じ名前のメンバーまたはオブジェクトを含めることはできません。

import MoneySyntax._
val amount: Double = 30.5
val RichMoney = 1

amount.dollars

したがって、 importMoneySyntax。_によってインポートされた暗黙のクラスと同じ名前の変数を定義した場合、その変数はコンパイルされません。

オブジェクトについても同じことが起こります。

import MoneySyntax._
val amount: Double = 30.5
object RichMoney

amount.dollars

7. 結論

この短い記事では、暗黙のクラスについて説明しましたそれらを使用してより優れた構文を作成する方法を確認し、それらの制限について学習しました。

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