第55回 クロージャ

関数に値を保持させる

今、関数に何か数字を与えると、
その関数を呼ぶたびに与えた数字を ++ してほしいとする。


イメージ的には、

print f(5), "\n"; # 5
print f() , "\n"; # 6
print f() , "\n"; # 7

こんな感じである。


純粋に、

use strict;

sub f {
  my $c = shift;
  $c++;
}

print f(5), "\n";
print f(),  "\n";
print f(),  "\n";

このように書くと、

結果:

5
0
0

もちろんこうなる。 $c は毎回作られるからである。

クロージャ

そこで、クロージャと呼ばれるものを使って
次のようなソースを書いてみる。

use strict;

sub h{
  my $c = shift;
  sub { $c++ };
};

my $h = h(5);
print $h->(), "\n";
print $h->(), "\n";
print $h->(), "\n";

結果:

5
6
7

仕組み

どういう仕組みになっているかというと、

こういうことである。

第16回 無名関数をもっと理解する - bingo_nakanishiの他言語出身者のためのPerl入門
↑ここで、関数を他の関数の引数として与えられることを紹介しましたが、
今回のように関数を返り値として使うこともできます。


今回は、この関数を返せるということをさらに一歩進めて、
その外側の変数を保持させるということをしています。

クロージャとは

このようにクロージャは、自分が作られたときの環境を保持できるという特性を持っている(今回は $cを保持した)。
さらに、その環境に変化も加えられる(今回の ++にあたる)。