1

私は Scala の柔軟性と簡潔さをとても気に入っています。この金額の定義では、次のようになります。

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

trait Currency
case object EUR extends Currency
case object USD extends Currency

インスタンスを簡単に作成できます。

val m1 = MoneyAmount(100, EUR)

スコープ内の次の定義を使用すると、さらに簡単になります。

implicit class DoubleMoney(amount: Double) {
  def apply(currency: Currency) = MoneyAmount(amount, currency)
}

val m2 = 100 (EUR)
val m3 = 100 (USD)

私の質問は次のとおりです。次のことが可能になる方法はありますか:

val m3 = 100 EUR // does not compile!

各通貨 (EUR、USD など) の関数を定義せずに?

4

1 に答える 1

0

上でコメントしたように、通貨をメソッドとして定義せずにこれを行うことができるとは思いません。ただし、メソッドを使用して Currency オブジェクトを定義することもできます。次に、これらのメソッドをトレイトで定義して、通貨とその変換が確実に一致するようにすることができます。

小さなワークシートの例を次に示します。

object Money {
  import scala.math.BigDecimal

  /** Wrap a BigDecimal with a Currency - doubles and money do not play nicely */
  case class MoneyAmount(amount: BigDecimal, currency: Currencies.Type) {
    override def toString: String = s"${amount} ${currency.symbol}"
  }

  /** Trait that lists all the available currencies */
  trait Currencies {
    /** Abstract type provided by the implementations */
    type Type

    def EUR: Type
    def USD: Type
  }

  /** Object that holds all the available currencies as case class objects */
  object Currencies extends Currencies {
    case class Type(symbol: String, decimalPlaces: Int)

    override val EUR = Type("EUR", 2)
    override val USD = Type("USD", 2)
  }

  /** Implicit conversion from Int to money about */
  implicit class IntToMoneyAmount(value: Int) {
    type Type = MoneyAmount

    private def makeAmount(currency: Currencies.Type) = MoneyAmount(BigDecimal(value), currency)

    override def EUR = makeAmount(Currencies.EUR)
    override def USD = makeAmount(Currencies.USD)
  }

  5 EUR                                           //> res0: Money.MoneyAmount = 5 EUR
}

これは非常に冗長で、Currencyトレイトなしで実現できますが、変換を追加せずに通貨を追加するリスクがあります。

于 2013-11-22T14:33:01.383 に答える