簡體   English   中英

Scala:改進的代數數據類型

[英]Scala: Refined Algebraic Data Types

o/

這可能是一個相當有趣的問題,並且可能會激發你們的創造力。

我想以一種我可以的方式對貨幣進行建模:

  • 類型上的模式匹配(=> 代數數據類型)
  • 在其中存儲一個數字金額
  • 使用精煉類型將值限制為正值,例如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

我希望我清楚地表達了我的意圖。 如果有圖書館這樣做,我很高興有人指出它,盡管我希望從自己的思考中學到一些東西。

你的意思是這樣的嗎?

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM