Lambdaカクテル

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

Invite link for Scalaわいわいランド

Perlのqw()みたいなやつがScalaにも欲しいので作った

追記3: Maven Central Repositoryにリリースした。

index.scala-lang.org

追記2: ライブラリ化した。Mavenにpublishする手続きをちびちびやっている。

github.com

追記: 実装おかしかったのでちょっと修正した

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という仕組みがある。

Redirecting…

元々は、s"value of n is: $n" みたいな表記をしたときに$nの部分に値を埋めてくれるという、だいたいの言語にある機能だ。そしてScalaは、この機構を自作できるように設計されている。

StringContextを拡張するメソッドとしてqwを定義しておき、渡ってきたargsを空白文字で区切りながらbufに追加していき、最終的にListが得られるという仕組みだ。ちゃんと変数もtoStringで展開されている。

暇があったらこれ単体でライブラリ化すると便利かもな〜と思いつつ、どうせ誰かがもうやってるんじゃないか??という思いもある。

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