追記3: Maven Central Repositoryにリリースした。
追記2: ライブラリ化した。Mavenにpublishする手続きをちびちびやっている。
追記: 実装おかしかったのでちょっと修正した
Perlにはqw()
という文字列のリストを構築するための便利な構文があって、以下の表現は等価だ:
("foo", "bar", "buzz", "qux")
qw(foo bar buzz qux)
文字列のリストをハードコードすることは時たまあるので、こういう構文があるのは非常に便利だ。そして、Scalaには(パッと思い付く限りでは)そういう構文が無いので、長々と書かなければならない:
val s = "foo" :: "bar" :: "buzz" :: "qux" :: Nil //もしくは val s2 = List("foo", "bar", "buzz", "qux")
ウーン、なんとかならないのか、と思ったところで無いものは無いので、欲しかったら作らなければならない。
extension (sc: StringContext) def qw(args: Any*): List[String] = val strings = sc.parts.iterator val expressions = args.iterator var buf = collection.mutable.ListBuffer(strings.next().split(" ")*) while strings.hasNext do buf.append(expressions.next().toString) buf.append(strings.next().toString.split(" ")*) buf.filterNot(_.isEmpty).toList val i = 12345 val lis = qw"foo bar $i buzz" lis.mkString(",") // => foo,bar,12345,buzz
できた。 Listにどんどんappendしていたりと最適な実装ではないと思うけれど、リファレンス実装ということで何卒。
実装の話
Scalaにはstring interpolationという仕組みがある。
元々は、s"value of n is: $n"
みたいな表記をしたときに$n
の部分に値を埋めてくれるという、だいたいの言語にある機能だ。そしてScalaは、この機構を自作できるように設計されている。
StringContext
を拡張するメソッドとしてqw
を定義しておき、渡ってきたargs
を空白文字で区切りながらbuf
に追加していき、最終的にList
が得られるという仕組みだ。ちゃんと変数もtoString
で展開されている。
暇があったらこれ単体でライブラリ化すると便利かもな〜と思いつつ、どうせ誰かがもうやってるんじゃないか??という思いもある。