引数なしのクロージャ

引数なしのクロージャをどう書くか

について・・・

上記Blogの前日記事への
みずしまさんのコメント

=> TypeName
はメソッドの引数専用の修飾子のようなもので、引数が名前渡し(call-by-name)であることを指定するものです。実装的には関数を作って渡してるわけですが、概念的には引数を評価しないまま関数に渡して、関数内部で必要になるたびに評価するイメージですね。引数無しの関数の場合、
() => TypeName
とすることになりますが、こっちの方はあまり使わない気がしますね。

を受けて実験してみた。

scala> val f: => Any = {"s"}
<console>:1: error: identifier expected but '=>' found.
       val f: => Any = {"s"}
              ^

と、こうなってしまうのを・・・以下のように

scala> val f:() => Any = {"s"}
<console>:4: error: type mismatch;
 found   : java.lang.String("s")
 required: () => Any
       val f:() => Any = {"s"}
                          ^

としてみたけどまだダメで・・・結局

scala> val f:() => Any = {() => "s"}
f: () => Any = <function>

とすれば、

scala> f
res0: () => Any = <function>

scala> f()
res1: Any = s

のようにうまくいった。

で、ここでさらに・・・

scala> var n = 5
n: Int = 5

の時

scala> def f1 = { "s" * n }
f1: String

とすれば、もちろん

scala> f1                  
res15: String = sssss

となるし、これを

scala> def f2 = f1
f2: String

こうしても、もちろん

scala> f2 
res16: String = sssss

scala> n = 8
n: Int = 8

scala> f2
res18: String = ssssssss

となる。
ここで、おもむろに、

scala> val f3 = f1
f3: String = ssssssss

などとした場合は、

scala> n = 2
n: Int = 2

としても、残念ながら

scala> f3
res20: String = ssssssss

となってしまうので、関数【オブジェクト】として変数に入れたい場合には

scala> val f4 = f1 _
f4: () => String = <function>

とする。
ちなみに、呼び出す時には

scala> f4
res23: () => String = <function>

ではなく

scala> f4()
res24: String = ss

となる。

最終的に

scala> n = 20
n: Int = 20

の場合には、

scala> f1
res26: String = ssssssssssssssssssss

scala> f2
res27: String = ssssssssssssssssssss

scala> f3
res28: String = ssssssss

scala> f4()
res30: String = ssssssssssssssssssss

となる。