アンダーバー"_"

全然意味がわからなかったんだけど、なんかわかった。

Scalaのライブラリを読んでいると、関数への引数に "_" を使っているのが目につく。

どうも、"_" は、無名関数を作成するショートカットらしい。

例えばこんなの。

List("abc", "def", "ghi").map(_(1))
List("abc", "def", "ghi").map(_.length)
List(1, 2, 3).filter(_ % 2 == 0)

こいつらは、ちゃんと書くと。

List("abc", "def", "ghi").map((x) => x(1))
List("abc", "def", "ghi").map((x) => x.length)
List(1, 2, 3).filter((x) => x % 2 == 0)

になる。
上記は、引数が1つだけの例だけど、引数が複数の場合も使える。

List(1, 2, 3, 4, 5).reduceLeft[int](_ + _)

これは、

List(1, 2, 3, 4, 5).reduceLeft[int]((a, b) => a + b)

と同じ。
"_" が登場する順番と、引数の順番が一致していないと起こられるっぽい。

例えば、

class ClassA {
  def methodA = "METHOD A"
}

class ClassB {
  def methodB = "METHOD B"
}

def hoge(f:(ClassA, ClassB) => String) = f(new ClassA, new ClassB)

な感じで、ClassAクラス、ClassBクラス、hoge関数を用意する。
以下の呼び出しは、OK。

hoge(_.methodA + " " +  _.methodB) // 結果: METHOD A METHOD B

最初の"_"には、ClassAが、最初の"_"には、ClassBが割り当てられる。

methodBと、methodAの呼び出しを逆にすると、いかのとおり、がっつり怒られる。

hoge(_.methodB + " " +  _.methodA)
<console>:6: error: value methodB is not a member of ClassA
       hoge(_.methodB + " " +  _.methodA)

あと、"_" に対して型指定もできる。

(_: int) + (_: String).length

これは、こんな無名関数を書いたのと同じ。

(a: int, b: String) => a + b.length