Scala:精代数数据类型

问题描述 投票:0回答:1

o /

这可能是一个非常有趣的问题,可能会激发您的创造力。

我想以一种可以的方式为货币建模:

  • 模式匹配类型(=>代数数据类型)
  • 在其中存储数值
  • 使用refined type将值限制为例如正值,例如val amount: Float Refined Positive
  • 具有预定义且不可变的三字符货币代码,如“ USD”

在一个实现中进行此操作的子集很容易,但是我发现创建一个允许如下所示类型的类型令人惊讶地困难:

def doSomething(currency: Currency): Unit {
  currency match {
    case BITCOIN => println("Oh, a cryptocurrency! And it is ${currency.amount} ${currency.code}!"
    case EURO => println("So we are from Europe, eh?")
  }
}

doSomething(new Currency.BITCOIN(123f)) // yielding "Oh, a cryptocurrency! And it is 123 BTC!"

val euro = new Currency.EURO(-42f) // compile error

我希望我明确了意图。如果有图书馆这样做,我很乐意指出这一点,尽管我希望从自己的思考中学到一些东西。

scala pattern-matching algebraic-data-types
1个回答
2
投票

您的意思是这样的吗?

import eu.timepit.refined.api.Refined
import eu.timepit.refined.auto._
import eu.timepit.refined.numeric.NonNegative
import eu.timepit.refined.string.MatchesRegex

sealed trait Currency extends Product with Serializable {
  def amount: Currency.Amount
  def code: Currency.Code
}

object Currency {
  type Amount = BigDecimal Refined NonNegative
  type Code = String Refined MatchesRegex["[A-Z]{3}"]

  final case class Euro(amount: Amount) extends Currency {
    override final val code: Code = "EUR"
  }

  final case class Dollar(amount: Amount) extends Currency {
    override final val code: Code = "USD"
  }
}

def doSomething(currency: Currency): Unit =
  currency match {
    case Currency.Euro(amount) => println(s"Euro: € ${amount}")
    case _ => println(s"Somenthing else with code ${currency.code} and amount ${currency.amount}")
  }

此作品:

doSomething(Currency.Dollar(BigDecimal(10))) 
// Somenthing else with code USD and amount 10
© www.soinside.com 2019 - 2024. All rights reserved.