ScalaのタプルとC#の匿名クラス

Scalaに触れ始めてからそれなりに時間が経ったが、関数型言語を一つも知らないためか、どうも手続型的なアプローチでコードを組んでしまうことが多い。

今悩んでいるのはタプル。タプルは便利なのだがタプルの各要素にアクセスするための「._1」「._2」が目障りでしょうがない。C#でこういうことをやるときは匿名クラスを使うことが多い。たとえば、

persons.select(p => new {Fullname = p.FirstName + " " + p.LastName, Age = p.Age})

など。Scalaにこういう機能は無い。

これを持ってしてScalaがダメという訳ではないはずだ。偉い人が作ったのだから、匿名クラス以外に何かもっと別の良いやり方があるはずだ。この記事ではタプル操作から「._1」「._2」を排除することを目指す。なぜ排除しなければならないか?それはコードを見たときに「._1」「._2」が何を表すかパッと見ただけでは分からないからである。

例その1:match

もしmatchさせる場面があれば話は単純だ。Tupleはケースクラスなのでパターンマッチが使える。

val p = ("takahashi", "tokyo", 20)
p match {
case (name, address, age) => println("hello, " + name + " your age is " + age + "yrs old.")
}

これなら何も問題ない。何をやっているか一目瞭然のコードとなる。

例その2:高階関数

どういう言語仕様になっているかいまいちよく分かっていないのだが、filterやmapをするときはいきなりcaseと書ける。このときはコードはブロック{} でないとダメなようだ。

val persons = (1, "nobita") :: (2, "draemon") :: (3, "kiteretsu") :: Nil
persons.filter(case (id, _) => id >= 2)

例その3:for文で回す

下記のように直感的に書けるらしい。

val persons = (1, "nobita") :: (2, "draemon") :: (3, "kiteretsu") :: Nil
for((id, name) <- persons){ println("id:"+id, "name:"+name) }

もっと他にも例を挙げようと思ったけど、パッと思いつく限りは上記の3つしかなかった。ただ、これらを組み合わせれば大抵のことは何とかなるのでは。