Lambdaカクテル

京都在住Webエンジニアの日記です

Invite link for Scalaわいわいランド

Scala 3のEnumとStringを相互変換する方法がやや不便

プログラミングにおけるEnumeration、略してEnumは列挙型とも呼ばれ、いくつかあるうちの特定の値しか取らない型を表現するために使われる型である。Enumはだいたいの言語で様々な形で実装されている。

さて、Scala 2までではEnumを使う際はやや特殊なクラスを利用する必要があった。

scala-lang.org

これの出来はあまり良くなかったので、ユーザはこれを独自に実装するか、適当な数字にalias typeをつけてごまかしたり、専用のライブラリを使ったりしていた。

github.com

嬉しいことに、Scala 3ではEnumがファーストクラスで提供されている。

docs.scala-lang.org

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を使いたいためである。

ben.kirw.in

Declineは賢いので、文字列から型Aに変換する方法を用意すれば、コマンドライン文字列からその型Aを復元して渡せるようになる。しかしながらScala 3のEnumにはまだ対応していないため、手でボイラープレートを書かなければならない。しかもenumのvalueOfは実行時例外を発するので、かなりダサい感じになってしまうな・・・という問題意識があるのであった。

追記

valuesを使うと配列がもらえるのでここから探すと良いとのことだった。

★記事をRTしてもらえると喜びます
Webアプリケーション開発関連の記事を投稿しています.読者になってみませんか?