引数なしの関数オブジェクト [Scala]
Scala で引数なしの関数オブジェクトを作る場合、基本的には以下のように「 () 」を仮引数の場所に書くことになる。
scala> { () => Console.println("Hello World!") } unnamed10: () => Unit = <function>
この「() =>」を省いてしまうと関数オブジェクトというよりも単にブロックとして実行されてしまう。
scala> { Console.println("Hello World!") } Hello World! unnamed11: Unit = ()
しかしこれを省いてもいい場面というのがあって、それは「() => Unit」型でなく「=> Unit」型として指定されているメソッド引数に渡す場合である(勿論矢印の右辺は Unit でなくても何でもいい)。
scala> def f(g: => Unit) { } f: (=> Unit)Unit scala> f { Console.println("Hello World!") } unnamed14: Unit = ()
Perl で高階関数を書くときにプロトタイプ指定をしてあげると呼ぶときに sub と書かなくてもよくなる、というのにちょっと似ているかもしれない。
それはともかく、これを使って前の記事 [1] の 3.times 構文を書き直すと以下のようになる。
scala> class Loop(n: int) { def times(x: => Unit): Unit = {for (i <- 1 to n) x } } defined class Loop scala> implicit def int2loop(n: int): Loop = { new Loop(n) } int2loop: (int)Loop scala> 3.times { Console.println("cheer"); } cheer cheer cheer unnamed15: Unit = ()
このようにこれは DSL っぽいことをするのに重宝する。Scala の Actor ライブラリでもこの型が活用されていて、このおかげであたかも Actor 用の特別な構文があるかのように見える(実際にはただのライブラリであって言語仕様に対する拡張ではない)。
なお型指定のときに「x: => Unit」というようにコロンと矢印の間には空白を挟まなければいけない。「:=>」は Scala の識別子になりうるので空白をはさまない場合はシンタクスエラーになる。
[1] http://blog.so-net.ne.jp/rainyday/2007-05-31
コメント 0