我有一个基本的枚举类型货币,这将包括所有交易的主要货币如EUR
,USD
,JPY
,等这段代码我可以写或产生一次。不过,我也想对所有货币对强劲枚举类型的组合如EURCHF
,USDCHF
等有Scala中的任何条款,让我建立这样一个动态派生枚举类型?我也可以用一些外部的脚本生成器来做……但我想知道是否有可能。
object Ccy extends Enumeration {
type Type = Value
val USD = Value("USD")
val CHF = Value("CHF")
val EUR = Value("EUR")
val GBP = Value("GBP")
val JPY = Value("JPY")
}
object CcyPair extends Enumeration {
type Type = Value
// ??? Ccy.values.toSeq.combinations(2) ...
}
Run Code Online (Sandbox Code Playgroud)
UPDATE使用接受的答案作为参考,这是我的解决办法实现:
import scala.language.dynamics
object CcyPair extends Enumeration with Dynamic {
type Type = Value
/*
* contains all currency combinations including the symmetric AB and BA
*/
private val byCcy: Map[(Ccy.Value, Ccy.Value), Value] =
Ccy.values.toSeq.combinations(2).map { case Seq(c1, c2) =>
Seq(
(c1, c2) -> Value(c1.toString + c2.toString),
(c2, c1) -> Value(c2.toString + c1.toString)
)
}.flatten.toMap
/**
* reverse lookup to find currencies by currency pair, needed to find
* the base and risk components.
*/
private val revByCcy = byCcy.toSeq.map { case (((ccyRisk, ccyBase), ccyPair)) =>
ccyPair -> (ccyRisk, ccyBase)
}.toMap
def apply(ccy1: Ccy.Value, ccy2: Ccy.Value): Value = {
assert(ccy1 != ccy2, "currencies should be different")
byCcy((ccy1, ccy2))
}
implicit class DecoratedCcyPair(ccyPair: CcyPair.Type) {
def base: Ccy.Type = {
revByCcy(ccyPair)._1
}
def risk: Ccy.Type = {
revByCcy(ccyPair)._2
}
def name: String = ccyPair.toString()
}
def selectDynamic(ccyPair: String): Value = withName(ccyPair)
}
Run Code Online (Sandbox Code Playgroud)
然后我可以做这样的事情:
val ccyPair = CcyPair.EURUSD
// or
val ccyPair = CcyPair(Ccy.EUR, Ccy.USD)
// and then do
println(ccyPair.name)
// and extract their parts like:
// print the base currency of the pair i.e. EUR
println(CcyPair.EURUSD.base)
// print the risk currency of the pair i.e. USD
println(CcyPair.EURUSD.risk)
Run Code Online (Sandbox Code Playgroud)
Scala 的Enumeration
. 对Value
内部函数的调用只是对Enumeration
的内部可变结构进行了一些修改。所以你只需要调用Value
每对货币。以下代码将起作用:
object CcyPair1 extends Enumeration {
Ccy.values.toSeq.combinations(2).foreach {
case Seq(c1, c2) =>
Value(c1.toString + c2.toString)
}
}
Run Code Online (Sandbox Code Playgroud)
不过工作起来不是很舒服。您只能通过withName
或values
函数访问这些值。
scala> CcyPair1.withName("USDEUR")
res20: CcyPair1.Value = USDEUR
Run Code Online (Sandbox Code Playgroud)
但是可以扩展此定义,例如,允许CcyPair.Value
通过一对Ccy.Value
s进行检索,或允许通过对象字段访问Dynamic
,或提供您可能需要的其他设施:
import scala.language.dynamics
object CcyPair2 extends Enumeration with Dynamic {
val byCcy: Map[(Ccy.Value, Ccy.Value), Value] =
Ccy.values.toSeq.combinations(2).map {
case Seq(c1, c2) =>
(c1, c2) -> Value(c1.toString + c2.toString)
}.toMap
def forCcy(ccy1: Ccy.Value, ccy2: Ccy.Value): Value = {
assert(ccy1 != ccy2, "currencies should be different")
if (ccy1 < ccy2) byCcy((ccy1, ccy2))
else byCcy((ccy2, ccy1))
}
def selectDynamic(pairName: String): Value =
withName(pairName)
}
Run Code Online (Sandbox Code Playgroud)
这个定义更有用一点:
scala> CcyPair2.forCcy(Ccy.USD, Ccy.EUR)
res2: CcyPair2.Value = USDEUR
scala> CcyPair2.forCcy(Ccy.EUR, Ccy.USD)
res3: CcyPair2.Value = USDEUR
scala> CcyPair2.USDCHF
res4: CcyPair2.Value = USDCHF
Run Code Online (Sandbox Code Playgroud)