scalaでEnum的なことをするときよくこんな感じで実装しますが
sealed abstract class Color
object Color {
case object Red extends Color
case object Blue extends Color
case object Green extends Color
}
結構↓みたいな使い方をした場合が多いです。
// 取ってきたデータ(StringやShortとか)からEnumに変換したい
scala> val red = Color("red")
red: Option[Color] = Some(Red)
// valueを持たせたい
scala> Color.Red.code
res17: String = #FF0000
こういう時一個traitを用意してEnumそれを継承するだけで便利になる気がします。
trait Enum[A <: { def name: String }] {
val values: List[A]
def apply(name: String): Option[A] = values.find(_.name == name)
}
sealed abstract class Color(val name: String, val code: String)
object Color extends Enum[Color] {
case object Red extends Color("red", "#FF0000")
case object Blue extends Color("blue", "#0000FF")
case object Green extends Color("green", "#008000")
lazy val values = List(Red, Blue, Green)
}
文字列以外も対応したい場合は EnumValue
を用意して、必要に応じて extends
した方が一番使いやすい気がします。
(こちらに参考しました!)
trait EnumValue {
type Value
val value: Value
}
trait Enum[A <: EnumValue] {
val values: List[A]
def apply(value: A#Value): Option[A] = values.find(_.value == value)
}
ただし values
をいちいち定義して case object
全部入れないといけないのが手間かかりますので…
そこはreflection使うとよりいい簡潔にかけると思いますが、また別の機会に試してみます。