プログラミングにおけるEnumeration、略してEnumは列挙型とも呼ばれ、いくつかあるうちの特定の値しか取らない型を表現するために使われる型である。Enumはだいたいの言語で様々な形で実装されている。
さて、Scala 2までではEnumを使う際はやや特殊なクラスを利用する必要があった。
これの出来はあまり良くなかったので、ユーザはこれを独自に実装するか、適当な数字にalias typeをつけてごまかしたり、専用のライブラリを使ったりしていた。
嬉しいことに、Scala 3ではEnumがファーストクラスで提供されている。
Enumはenum
キーワードを使って定義でき、そのまま型に表れることができる。
enum Color { case Red, Green, Blue } def complementary(c: Color): (Color, Color) = ... complementary(Color.Red) // => (Green, Blue)
そして、toString
を使うことで、Enumから文字列表現を得ることも簡単にできる:
Color.Red.toString() // => "Red"
逆に、文字列からEnumを構築するにはvalueOf
を使う:
Color.valueOf("Red") // => Color.Red
valueOf
が型安全じゃない
さて、valueOf
は型安全ではない。"Foo"
などを渡すと実行時にコケてしまう。
そこで、型安全にvalueOf
を使うにはscala.util.control.Exception.allCatch
を使わなければならない・・・。
import scala.util.control.Exception.allCatch def colorify(s: String): Option[Color] = allCatch opt { Color.valueOf(s) } colorify("foo") // => None
(関係ないとのことだった)できれば、ビルトインで型安全にvalueOf
という名前からして、おそらくLiteral Types関連の機能を呼び出しているのかもしれない。String => Option[enum]
になるようなメソッドが生えていてほしい・・・。
文脈
なんでこんな機能が欲しいかというと、CLIパーサライブラリであるDeclineでEnumを使いたいためである。
Declineは賢いので、文字列から型A
に変換する方法を用意すれば、コマンドライン文字列からその型A
を復元して渡せるようになる。しかしながらScala 3のEnumにはまだ対応していないため、手でボイラープレートを書かなければならない。しかもenumのvalueOf
は実行時例外を発するので、かなりダサい感じになってしまうな・・・という問題意識があるのであった。
追記
valuesというArrayでかえるmethodはあるので、それで
— Kenji Yoshida (@xuwei_k) 2023年5月19日
.values.find(_.toString == name) // Optionになる
とするか
scala.deriving.Mirror.SumOf
のメタプロ機能使って独自に作るか、じゃないですかね
"おそらくLiteral Types関連の機能"
は全然関係ないです
values
を使うと配列がもらえるのでここから探すと良いとのことだった。