Home > 技術 > いろんな言語のクロージャ

いろんな言語のクロージャ

以前にJavaScriptのクロージャを無名関数、クロージャ、そしてレキシカルスコープへでまとめたのですが、今回は他のスクリプト系言語のクロージャを取り上げてみたいと思います。

Rubyのクロージャ

Rubyで関数と呼ばれるものは必ずクラスに所属しています。
トップレベルな空間にメソッドを定義するとObjectクラスに所属するメソッドになるようです。

そしてRubyのクロージャは実際には関数オブジェクトではなく、Procというクラスのインスタンスを返すようです。
Proc.newにはブロックを渡しこれをオブジェクト化したものを返すとクロージャが出来上がるというのが大体のイメージになります。

小難しいので以下のコードを見てください。

まず外側にある関数get_closureにはローカル変数としてcountがあります。
そしてreturnでProcインスタンス、つまりクロージャを返すようにしています。

このクロージャを取得すると呼び出すたびにブロックに渡された引数をcountに加算していきます。
JavaScriptのようにreturn function(){}のように無名関数を渡すのとちょっと違い、ブロックオブジェクトというところが難しいところですね。

そしてProc.new意外にもクロージャを作れるものとしてlambdaprocがあります。
書き方は以下の感じ。

※補足
Proc.newとlambdaの違いは、
lambdaのほうはブロックに渡された引数の数とcallメソッドが呼ばれたときの引数の数をチェックするが、Procのほうにはnilが入るみたいです。

[via]
Rubyのblock、Proc、lambdaを理解する - 医者を志す妻を応援する夫の日記

■参考リンク
Rubyの「クロージャ」再考 - バリケンのRuby日記 - Rubyist
まつもと直伝 プログラミングのオキテ 第5回(3) - まつもと直伝 プログラミングのオキテ:ITpro

Perlのクロージャ

まずブロックスコープを作成し、その中で$count変数とクロージャとなる$closure変数に関数を代入しています。
こうすることで$count変数は$closure関数が参照している間解放されずにスコープに存在し続けます。

Rubyの場合はブロックをreturnしていましたが、Perlではブロックで囲った中で関数を代入するという方法でできるんですね。
でもこの方法以外にもPerlだからいろんなトリックがありそうです。。。

■参考リンク
Perl5編 第28章 クロージャ
クロージャの定義 - Perl入門〜サンプルコードによるPerl入門〜

Pythonのクロージャ

Pythonの場合は先ほどRubyで出てきたlambdaを使うかローカル関数を定義してそれを返すかの2通りのようです。

ただPythonでクロージャを作る場合にはちょっとだけ注意する点があります。

僕はPythonのバージョン2.5.1を使っているのですが、このバージョンでは内側にある関数内で外側にある関数の変数に値を代入できません。
Pythonでは代入とはローカル変数に対して実行されるので、内側の関数内でcount += argとすると、

UnboundLocalError: local variable 'count' referenced before assignment

となり未初期化変数への加算となりエラーになってしまいます。
これを防ぐのにリストに入れるというのがあるようです。(トリッキーだな〜w)

Python3からはnonlocalとローカル変数ではないという情報を変数にもたせることができるので、
nonlocal count += argと書けるみたいです。

■関連リンク
Python 3.0 Hacks:第1回 nonlocalでクロージャが便利に|gihyo.jp ... 技術評論社
お気楽 Python プログラミング入門:第3回再帰定義と高階関数
pythonでクロージャ
Pythonでのクロージャは? - def __mopemope__(self, *args, **kwargs):

JavaScriptのクロージャ

普段使い慣れているだけあって、一番理解しやすいのがJavaScriptのクロージャです。
関数オブジェクトをreturnできるので、クロージャ=関数という感覚が掴めるので馴染みやすいクロージャですね。

無名関数を即時実行してclosure変数にはreturnされた関数オブジェクトが格納されています。
これでclosure関数を呼び出すとcount変数がレキシカルスコープになり、引数の値が加算されていく感じです。

ActionScript3のクロージャ

ActionScriptにはFunctionという型があるので、無名関数を作ってreturnするだけでクロージャが出来上がる。
JavaScriptとほぼ一緒ですね。

Javaのクロージャ

Java7でクロージャが入る入らないという話が以前盛り上がりましたが、あれってどうなったんだろう。。。

現時点でJavaにクロージャはありませんが、それっぽいものは存在します。
無名関数ではなく無名クラスです。

以下がクロージャ的無名クラスを返すクラスである。
このクラスのgetCounterメソッドを実行すると、return new Counter()と
何かクラスのようなものをnewしている。

本来ならreturn new (){}としたいところなのだが、受け取り側でどのような型で取得すればよいのが分からない。
静的言語ゆえな面倒くささはあるのだが、interfaceかClassを事前に定義しておき、
それを指定してnewする感じで使うのが一般的にようです。
今回はinterfaceが上位型の無名クラスなので上位クラスはjava.lang.Objectになる。

こっちは無名クラスを使うほう。

クロージャ(無名クラス)を取得しているgetCounterの型はClosureClass.Counterになるので
変数にもこの型を指定している。

まとめ

いろんな言語のクロージャを取り上げてみたが、プログラム言語ごとに仕様は違うし分かりやすいものもあれば
分かりにくいものも存在する。
Java7のクロージャの解説記事Java 7のクロージャ(BGGA版)のプロトタイプを試してみた(2)を見てみたのですが、さっぱり分からなかった。

ってかクロージャなのか?w

今回解説した内容意外でもさまざまな方法でクロージャを作成する方法があるかもしれません。
そうゆうハックを探すのもプログラム言語を理解するためには重要ですね。

■関連記事
クロージャのスコープは関数オブジェクト単位だよ
JavaScriptでちょっと面白いコード - 式クロージャ

Trackback:0

TrackBack URL for this entry
http://hisasann.com/cgi-bin/mt/mt-tb.cgi/1207
Listed below are links to weblogs that reference
いろんな言語のクロージャ from HouseTect, JavaScriptな情報をあなたに

Home > 技術 > いろんな言語のクロージャ

Tag cloud
月別アーカイブ
Powered by
Powered by
Movable Type Commercial 4.261

Page Top