それをはじめてみたのはPerlの書籍だったでしょうか。
最初は、クロシージャと読み間違え、プロシージャの誤植だと思ったのですが違いました。
その頃は、そんなもの無くてもプログラミング出来てました。(今もやってますが)
時は流れて、JavaScriptが大流行、Java8がリリースされる頃になって
やたら?たまに聞くようになってとっても気になるクロージャですが、
どうもいつまで経ってもわかった気になりません。
もちろん、色々なサイトや書籍で事あるごとに説明を読むのですが、
私の理解では、ざっくり関数内のstatic変数? くらいの認識までにしか至らずに今まで参りました。
自分のあずかり知らぬところで世の開発者の皆様はクロージャーを日々駆使しているのでは無いかと思うと夜も眠れません。(もちろん嘘ですが)
何かそのせいで、自分のコーディングは日々回り道をしているのではととても気になります。
(Javaのインターフェースが分かった時には、パーン!みたいな感動があったので、もしかしたらそのようなことがあるのではと思ってます)
前置きが長くなりましたが、テラテイルだからこそこのような質問に答えてくれる方がいるに違いないと思い、恥を忍んで質問いたします。
他のサイトや書籍で読める説明的な説明はいりません。
クロージャに関して、以下の様なことを教えて下さい。
- クロージャってひとことで言うと何? (多少語弊のある表現でも構いません)
- 分かった!って思った瞬間を覚えていたら、その時のことを教えて下さい。
- 結局、どんな時に使いますか? 短いコードで表せたら知りたいです。
- タグに上げた以外でクロージャを使える言語はありますか?
- もしよろしければ、理解のための例題をくださると嬉しいです。
- 上記以外で、理解のためのに必要なことがあれば、とにかく教えて下さい。
全てでなくてもいいです、答えられることだけで構いません。
お忙しい中めんどくさい質問ですいませんが、よろしくお願い致します。
追記 2016/07/14 1:00
言語ごとに多少なりとも解釈や用途が違うということがあると思います。
その場合、統括的な解説なのか、言語特有な説明なのか明示して頂けると齟齬もなくなるかと思います。
では、改めてよろしくお願い致します。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答8件
0
ベストアンサー
クロージャをひとことで・・・(その後が長い)
クロージャをひとことで言うと「定義が評価された時の環境を閉じ込めて一緒に包んでしまうこと」です。
ここで一番大事なのは環境です。環境知らずにしてクロージャは語れません。ほとんどの言語において、環境は「静的スコープ(static scope)での変数(または値)の集合体」のことです。静的スコープはレキシカルスコープ(lexical scope)とも呼ばれています。構文から静的に決定されるスコープなので構文的(lexical)と呼んでいるだけであり、静的スコープとレキシカルスコープは同じモノです。
※ Emacs Lisp等、動的スコープ(dynamic scope)を採用している言語もありますが、少数です。
クロージャを語るつもりが、環境やら静的スコープとか出てきました。まず、スコープとは何かというと変数が見える範囲(視野)の事です。下記例を見てみましょう。(以下は静的スコープであるJavaScript(ECMAScript 2016)での例になりますので、動的スコープでは全く異なることに注意してください)
JavaScript
1// 大域スコープ ===> 2"use strict"; 3let x = 1; 4const f = function() { 5 // 関数 f スコープ ---> 6 let y = 2; 7 if (true) { 8 // ブロック スコープ ~~~> 9 let z = 3; 10 console.log(x, y, z); // => 1 2 3 11 // <~~~ ブロック スコープ 12 } 13 // <--- 関数 f スコープ 14}; 15const g = function() { 16 // 関数 g スコープ ---> 17 let y = 42; 18 f(); 19 console.log(y) // => 42 20 // <--- 関数 g スコープ 21}; 22g(); 23// <=== 大域スコープ
JavaScriptでは主に大域スコープ(global scope)、関数スコープ(function scope)、ブロックスコープ(block scope)の三つがあります(他にevalスコープ(eval scope)とモジュールスコープ(module scope)がありますが、ここでは省略します。なお、名称はECMAScript 2016仕様書での○○DeclarationInstantiationとなっているものから取ってきています)。変数は宣言された場所のスコープに関連づけられ、そのスコープの範囲内で有効になります(var
で宣言された場合のみ特殊で、ブロックスコープ上であっても一番間近の外側にある大域スコープまたは関数スコープに関連づけられます)。上では、x
は大域スコープ、y
は関数スコープ、z
はブロックスコープが有効範囲です。しかし、スコープは外から内へ浸食しており、内側のスコープは外側のスコープを見ることができます。ですので、x
やy
もz
と同じように一番内側のブロックスコープでもアクセスできます。同時に、並列にあるスコープはそれぞれ独立しています。ですので、関数g
内のy
は関数f
内のy
への代入に影響を受けません。
※ スコープの種類や名称は言語によって異なります。
※ これはJavaScriptの場合であって、他の言語でも同じとは限りません。例えばRubyは、メソッドスコープから一番外側のトップスコープにあるローカル変数は見えません。
また、内側のスコープで外側のスコープと同じ名前の変数が宣言された場合は、その内側のスコープでのみ有効になる別の変数になります。
JavaScript
1// 大域スコープ ===> 2"use strict"; 3let x = 0; 4if (true) { 5 // ブロックスコープ ~~~> 6 let x = 1; 7 console.log(x); // => 1 8 // <~~~ ブロックスコープ 9} 10console.log(x); // => 0 11// <=== 大域スコープ
大域スコープのx
とブロックスコープのx
は別の物であるため、大域スコープのx
は変更されません。
このように、各スコープでわかれたそれぞれの場所を環境と言います。それぞれの環境にはそのスコープで宣言された変数が束縛されており、また、外側にどんな環境があるかも知っています(外側の環境をどんどん繋いでいく仕組みをスコープチェーンといいます)。
ここでもう一つ重要な概念を話さなければなりません。それは環境の寿命、つまり、そのスコープにある変数の寿命です。スコープは内側に侵食していますが、外側にはみ出すことはできません。つまり、スコープ内の処理を全て終えれば、そのスコープからしか見えない変数はアクセスができなくなる=破棄してもよいということです。一番最初の例を見てください。ブロックスコープを処理するときは、関数f
スコープも大域スコープも終わっていることはありません。ですが、ブロックが終わればz
は用済みですし、関数f
も終われば、関数f
だけ有効なy
も用済みです。アクセス不可能な変数をいつまでも保持するのはメモリの無駄ですので、そのスコープの環境が破棄され、全ての変数はいずれGCに回収されます。
※ C言語のstaticローカル変数などスコープが終わっても破棄されず、その変数だけ次回に再利用される場合もあります。
ここまではC言語のようなクロージャが無い言語でも同じ事です。では、クロージャは上のことと何が違うのか?を見ていきます。
JavaScript
1// 大域スコープ ===> 2"use strict"; 3const f = function() { 4 // 関数 f スコープ ---> 5 let x = 0; 6 const g = function() { 7 // 関数 g スコープ ---> 8 x++; 9 return x; 10 // <--- 関数 g スコープ 11 } 12 return g; 13 // <--- 関数 f スコープ 14} 15const c = f(); 16console.log(c()); // => 1 17console.log(c()); // => 2 18console.log(c()); // => 3 19// 大域スコープ ===>
さてx
は関数f
スコープです。先ほどの話では関数f
が終わったらx
も破棄されると言うことでした。関数g
内でx
を見ていますが、最初の例のように、もし関数f
内で実行される場合であれば、関数f
は終了していないので問題ありませんでした。あれ、でも待ってください。関数f
は戻り値として関数g
を返していて、定数c
に代入してます。つまり、関数g
の中身は関数f
が終わっても、定数c
として使用できると言うことです。後から中身だけ使おうとしたら、x
がある外側の環境がすでに破棄されていた…となってしまいます。
そこをうまくしてくれるのが我らがクロージャです。クロージャは関数g
が作られるまさにそのときの環境を一緒にくっつけて(閉じ込め、包み込んで)くれます。もともとは、関数f
スコープの環境は関数f
が終われば全て破棄される予定でしたが、関数g
(の中身)がその環境をまだ使うよと言って、破棄するのを防いでくれるようになるのです。こうして、関数f
が終わった後も、その中にあったx
は破棄されず、関数g
の中身を受け継いだ定数c
が関数として呼ばれるときに、x
を正常に使えるようになると言うことです。あ、もちろん、いつまでも保持するわけではありません。定数c
が破棄されれば、くっつけていた環境もいらなくなるので破棄されます。
ということで、最初のひとことで言っていた「環境の包み込み」の所に戻るというわけです。そして、包み込んだ環境を一緒に持ち出せる所がクロージャの最も重要な所と言っても過言ではありません。
###JavaScriptでクロージャである関数とクロージャではない関数
結論から言いますと、JavaScriptでの全ての関数(名前有り無しなどに関わらず)はクロージャを必ず含んでいます。理由は二つあります。一つは、JavaScriptは関数定義時にその中身を一切評価しないため、中で外側の環境にある変数を使っているかわからないと言うこと。もう一つは、その関数が現在のスコープが終了した後にも使われる事になるかを定義時に判断できないと言うこと。この二つの理由により、JavaScriptエンジンはその関数がクロージャとして動く必要があるのか、それともクロージャでなくても良いのかを関数が作成される定義時に判断することができないからです。
※ 他の言語も同じとは限りません。他の方が示したようにPHPでは普通の関数をクロージャにするかしないかをuseキーワードで選択できます(ただし無名関数は必ずクロージャになる、というよりClosureのインスタンスを作るのが無名関数であるらしい)。
###JavaScript以外のクロージャ
クロージャも実は色々種類があり、実装も様々です。上のことは他の言語でもだいたい同じように言えますが、細部が異なります。
- Rubyは無名関数ではなくブロック(do ~ end)がクロージャを作ります。クロージャの和訳が「関数閉包」となっていますが、何かしらの処理を定義された場所の環境と一緒に持ち出すことができるのであれば、関数であるかどうかは関係ありません。
Ruby
1// Proc.new は無名関数を作る構文ではなく、Procを作るただのメソッド呼び出し 2def f 3 x = 0 4 g = Proc.new do 5 x += 1 6 x 7 end 8 g 9end 10 11c = f 12puts c.call 13puts c.call 14puts c.call
- Javaのラムダおよび無名クラスはfinalまたは実質的finalしか内部で使えず、値または参照値をコピーしているだけであり、環境を含んでいるわけではありません。つまり、Javaは本当のクロージャを実装していません。
- C++はキャプチャによって外側のスコープの変数を見ることができますが、各変数のコピーまたは参照を渡しているだけであり、環境を含んでいるわけではありません。特に参照キャプチャは外側のスコープが終了すると寿命が尽きるようなローカル変数に使った場合、容易に壊れます。つまり、C++は本当のクロージャを実装していません。
C++
1// やってはいけない例 2#include <functional> 3#include <iostream> 4 5std::function<int(void)> f() 6{ 7 int x = 0; 8 auto g = [&x]() { 9 x++; 10 return x; 11 }; 12 return g; 13} 14 15int main() 16{ 17 auto c = f(); 18 std::cout << c() << std::endl; 19 std::cout << c() << std::endl; 20 std::cout << c() << std::endl; 21 return 0; 22}
- Haskellは遅延評価という仕組みであるため、束縛している変数が実際に評価されるときにはスコープが終了した後になる場合があります。そのため、そのときの各変数のコピーでは無く、環境自体を含んでいる必要があります。つまり、Haskellは本当のクロージャを実装しています。ただし、immutableという性質上、JavaScriptのカウンタの例のようなことはできません。
- Pythonはちょっと特殊っぽいです。調査中。
- Schemeはクロージャの元祖らしいです。
投稿2016/07/14 14:33
編集2016/07/14 22:25総合スコア21741
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
多少語弊のある表現でも構いません
とあるので、砕けて言ってみるとすごく単純なもので、
関数の中にある関数がクロージャです。
Javascript
1function outer() { 2 var foo = "outerスコープの変数" 3 function inner() { 4 console.log(foo); 5 } 6}
内側のinner関数がクロージャです。
外側のouter関数はエンクロージャと言います(enclose = "囲む" という意味)。
クロージャ自体の意味はそれだけです。
そして、クロージャの外に宣言されている foo 変数をクロージャ内でも参照できます
ということ。一見普通のようなことです。
クロージャの理解をややこしくしているのは、クロージャの用途が良く分からないからです。
「で、これの何が嬉しいの?」となるからです。
そこは他の回答者の方々の例が参考になると思います。
使いどころは、変数をprivate
にできるということだと思います。
Javascriptなどは private というものがありませんので、
private を実現しようと思うと、クロージャを使う以外方法がありません。
Javascript
1function createCounter() { 2 var count = 0; 3 4 return function() { 5 return ++count; 6 }; 7}; 8 9var counter = createCounter(); 10console.log(counter()); // 1と表示 11console.log(counter()); // 2と表示 12console.log(counter()); // 3と表示
こうするとcreateCounter内のcount変数はprivateになるわけです。
この変数にアクセスできるのは、createCounter内にあるクロージャだけです。
createCounterは、そのクロージャ関数を戻り値としています。
ここで奇妙なことが起きています。
上記の、var counter = createCounter();
の部分。
counter変数が参照しているのは
Javascript
1function() { 2 return ++count; 3}
という関数のはずですが、countってどのcount変数?ということになります。
当然、createCounterにあるcountです。
クロージャはエンクロージャ内のローカル変数の参照も含んだものになります。
一番最初の例で、クロージャの外に宣言されている変数をクロージャ内でも参照できます。
と説明しましたが、これはクロージャ関数をreturnして外に放り出しても同じことになります。
ややこしいですねぇ。。。
これを利用するとこんなこともできます。
Javascript
1function createCounter(start) { 2 return function() { 3 return start++; 4 }; 5}; 6 7counter1 = createCounter(1); 8console.log(counter1()); // 1と表示 9console.log(counter1()); // 2と表示 10console.log(counter1()); // 3と表示 11 12counter2 = createCounter(10); 13console.log(counter2()); // 10と表示 14console.log(counter2()); // 11と表示 15console.log(counter2()); // 12と表示
start変数はエンクロージャの物ですが、クロージャ内にちゃんと組み込まれてますね。
Javaに精通されているようですので、これをJavaっぽく書いてみると
すごく普通に見えます。
Javascript
1var Counter = function(start) { 2 this.get = function() { 3 return start++; 4 } 5} 6 7var counter = new Counter(1); 8console.log(counter.get()); // 1と表示 9console.log(counter.get()); // 2と表示 10console.log(counter.get()); // 3と表示 11 12var counter = new Counter(10); 13console.log(counter.get()); // 10と表示 14console.log(counter.get()); // 11と表示 15console.log(counter.get()); // 12と表示
今まので例は、このコードを以下のようにしてるようなものです。
Javascript
1var counter = new Counter(1).get; 2console.log(counter()); // 1と表示 3console.log(counter()); // 2と表示 4console.log(counter()); // 3と表示
投稿2016/07/14 04:01
編集2016/07/14 04:20総合スコア4666
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
maisumakunさんの回答につけたコメントの補足をこちらに書いてみます.PHPのクロージャはやはり少し特殊なので,JavaScriptと対比します.
最新の外部の変数の値を常に参照する
これが一番わかりやすいですね.
php
1<?php 2$value = 1; 3$closure = function () use (&$value) { 4 ++$value; 5 echo "Inside: value is $value\n"; // 1, 2 6}; 7--$value; 8$closure(); 9$closure(); 10echo "Outside: value is $value\n"; // 2
javascript
1var value = 1; 2var closure = function () { 3 ++value; 4 console.log('Inside: value is ' + value); // 1, 2 5}; 6--value; 7closure(); 8closure(); 9console.log('Outside: value is ' + value); // 2
最新の外部の変数の値を参照するが,内部で起こった変更は無視する
この場合には,クロージャの呼び出しごとにクロージャを内部的に作って実行する必要があります.作ってすぐに使い捨ての形で実行しているので,この形を即時実行といいます.その際,現在のvalueの値を引数として毎回与える必要があります.あくまで値として渡す引数なので,これに対する変更は外部や次の自分自身の実行には影響を与えません.
php
1<?php 2$value = 1; 3$closure = function () use (&$value) { 4 return (function ($value) { 5 ++$value; 6 echo "Inside: value is $value\n"; // 1, 1 7 })($value); // この書き方はPHP7.x以降 8}; 9--$value; 10$closure(); 11$closure(); 12echo "Outside: value is $value\n"; // 0
JavaScript
1var value = 1; 2var closure = function () { 3 return (function (value) { 4 ++value; 5 console.log('Inside: value is ' + value); // 1, 1 6 })(value); 7}; 8--value; 9closure(); 10closure(); 11console.log('Outside: value is ' + value); // 0
クロージャが作られたときの外部の変数の値を使用するが,内部で起こった変更は保持する
さっきのパターンの逆で,最初の1回だけクロージャを即時実行し,そのクロージャが作られたときのvalueの値を保持しようというものです.JavaScriptでは引数として渡すしかありませんが,PHPではuseで渡すこともできるので,今回はこちらで書いてみました.内部のクロージャはそのvalueに対しての参照を持つので,自分自身の次の実行には影響を与えます.
php
1<?php 2$value = 1; 3$closure = (function () use ($value) { 4 return function () use (&$value) { 5 ++$value; 6 echo "Inside: value is $value\n"; // 2, 3 7 }; 8})(); // この書き方はPHP7.x以降 9--$value; 10$closure(); 11$closure(); 12echo "Outside: value is $value\n"; // 0
javascript
1var value = 1; 2var closure = (function (value) { 3 return function () { 4 ++value; 5 console.log('Inside: value is ' + value); // 2, 3 6 }; 7})(value); 8--value; 9closure(); 10closure(); 11console.log('Outside: value is ' + value); // 0
クロージャが作られたときの外部の変数の値を常に使用する
これまでの応用です.PHPの場合はあっさり書けますが,JavaScriptがかなりややこしいですね…
php
1<?php 2$value = 1; 3$closure = function () use ($value) { 4 ++$value; 5 echo "Inside: value is $value\n"; // 2, 2 6}; 7--$value; 8$closure(); 9$closure(); 10echo "Outside: value is $value\n"; // 0
JavaScript
1var value = 1; 2var closure = (function (value) { 3 return function () { 4 return (function (value) { 5 ++value; 6 console.log('Inside: value is ' + value); // 2, 2 7 })(value); 8 }; 9})(value); 10--value; 11closure(); 12closure(); 13console.log('Outside: value is ' + value); // 0
投稿2016/07/14 02:52
編集2016/07/14 03:48総合スコア5223
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
解説する上でわかりやすいので、あえてPHPで説明します(基本的な文法構造はC言語系で、変数名はドルで始まります)。
まず、PHP 5.3以降では、無名関数を作って変数に代入することができるようになりました。
php
1$func = function($arg1, $arg2){ 2 return $arg1 * $arg2; 3};
これはただの無名関数ですが、use
という構文を使って無名関数が宣言された環境の変数を取り込むことができます。
php
1// 説明の都合上、PHP 5.3前提のコードです 2$some_array = array(); 3$closure = function($arg1, $arg2) use (&$some_array){ 4 $some_array[$arg1] = $arg2; 5 return $arg1 * $arg2; 6};
このようにしてから、$closure
だけほかのスコープに持ち出しても、$some_array
にはアクセスできるままとなります。このように、「別のものへの参照を組み込んだ」関数がクロージャです。
なお、PHPやC++では明示的に外側への参照をする必要がありますが、他の多くの言語では外側の変数を勝手に参照してくれるので、概念説明という意味では逆にわかりづらいです。
投稿2016/07/14 01:15
総合スコア146401
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/07/14 02:02 編集
2016/07/14 03:00
2016/07/14 03:06

0
クロージャの解説を読んでも理解しにくいのは、おそらくたいていの解説では「クロージャをたかだか1つしか生成していない」せいではないかと思います。
クロージャは、1つだけ生成してもあまり有難みがわかりません。
これはオブジェクト指向でも同じで、クラスから1つだけオブジェクトを生成してもピンとこないのではないでしょうか。一度クラスを定義したら、クラスからいくつも同じ性質のオブジェクトを生成できるのがオブジェクト指向の利点です。
クロージャもそれは同じで、一度元になる関数(というべきか?)を定義してしまえば、同じ性質のクロージャをいくつも生成できるところに利点があります。
単純なカウンタを例に見てみましょう。
まずはじめにグローバル変数を参照する例を見てみます。
javascript:グローバル変数を利用した例
1var globalValue = 0; 2 3function globalCounter(){ 4 function inner(){ 5 return globalValue++; 6 } 7 return inner; 8} 9 10var g1 = globalCounter(); 11g1(); // -> 0 12g1(); // -> 1 13 14var g2 = globalCounter(); 15g2(); // -> 2 16g2(); // -> 3
この例では、関数g1も関数g2も同じglobalValueを参照しているので、g2()を呼び出したとき、以前にg1()がカウントした値の続きからはじまっています。
次にクロージャを利用した例です。
javascript:クロージャを利用した例
1function counter(){ 2 var value = 0; 3 function inner(){ 4 return value++; 5 } 6 return inner; 7} 8 9var f1 = counter(); 10f1(); // -> 0 11f1(); // -> 1 12f1(); // -> 2 13 14var f2 = counter(); 15f2(); // -> 0 16f2(); // -> 1
関数f1,f2はそれぞれ独立したvalueという変数を参照しているので、f1とf2は独立したカウンタとして動作しています。
変数valueは、f1とf2それぞれに独立した変数としてf1,f2の中に閉じ込められているのです。
このようにクロージャを使うことにより、状態を内部にもったオブジェクトを作成することができます。
あえて「オブジェクト」という用語を使いましたが、関数型言語におけるクロージャは、オブジェクト指向におけるオブジェクトと考えることが可能です。
上記の例でいえば、関数counterがクラス、関数f1,f2がそれぞれオブジェクトと考えられます。
投稿2016/07/19 06:01
編集2016/07/19 06:04総合スコア314
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

退会済みユーザー
2016/07/22 14:05

0
クロージャってひとことで言うと何? (多少語弊のある表現でも構いません)
相当に語弊のある表現ですが、クロージャとは「レキシカルなスコープを生成する機能」だと理解しています。
分かった!って思った瞬間を覚えていたら、その時のことを教えて下さい。
↓これです!
javascriptに関する質問です。 a=1; function hoge(){ var a=2; … - 人力検索はてな
結局、どんな時に使いますか? 短いコードで表せたら知りたいです。
他の方の回答例のほかに、javascriptだとthisを束縛する時とかに使えないこともないです。
javascript
1function Person() { 2 var self = this; // `self` の代わりに `that` を選ぶこともあります。 3 // どちらかに統一するようにしましょう。 4 self.age = 0; 5 6 setInterval(function growUp() { 7 // このコールバックは、期待されるオブジェクトの値を 8 // `self` 変数で参照します。 9 self.age++; 10 }, 1000); 11}
タグに上げた以外でクロージャを使える言語はありますか?
Pythonです!
pythonと関数型プログラミング - 愚鈍人
もしよろしければ、理解のための例題をくださると嬉しいです。
上記以外で、理解のためのに必要なことがあれば、とにかく教えて下さい。
↓これが分かりやすいのではないかな、と。
束縛変数は関数内部でしか使用されないため、そのすべての出現箇所の名前を変えても関数の意味は変わりません。
自由変数は束縛変数のように勝手に名前を変更することはできません。
開いた関数が環境から自由変数の値を取り込むことで閉じた関数となるというところがクロージャを理解する上でのキーとなります。
投稿2016/07/14 03:15
総合スコア37301
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/07/14 10:59
2016/07/19 01:00

0
クロージャと言うからには「何か」を閉じているはずです。
ということは「何か」が開いていて、それが閉じます。
そして「何か」は関数です。
関数内部に、外部で定義された変数がある関数を「開いている」と表現します。
ない関数を「閉じている」と表現します。
fo() = return a + 1 // 開いている fc(x) = return x + 1 // 閉じている
開いている関数は、外部で変数が定義された文脈でしか実行できません。
fo() = return a + 1 y = fo() // エラー
開いている関数に、文脈を持たせてやると、閉じることができます。
close_fo() = a = 1 // 文脈 fo() = return a + 1 // 開いている関数 return fo f = close_fo() // 閉じた関数がもらえる
この、「開いている関数に実行文脈をつけて閉じたもの」をクロージャと呼びます。
クロージャの使いみちによくカウンタが例に出てきます。
make_counter() = count = 0 f() = print (count) count = count + 1 return return f
これはクロージャを使わずとも、
count = 0 f() = print (count) count = count + 1 return
と書けます。
しかし、countに他からアクセスし放題ですし、
カウンタが複数必要な時、名前が衝突して困ります。
count1 = 0 f1() = print (count1) count1 = count1 + 1 return count2 = 0 f2() = print (count2) count2 = count2 + 1 return
クロージャなら
make_counter() = count = 0 f() = print (count) count = count + 1 return return f f1 = make_counter() f2 = make_counter()
投稿2016/07/14 00:27
編集2016/07/14 02:20総合スコア13553
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
クロージャという言葉ではあまり表現しませんが、C# のラムダ式もそうです。
それが作られた環境をそのまま持って行く式とでも言いましょうか。
例えばローカル変数 a が存在する関数内で別の関数 f を宣言します。f 内では a を使用します。
f を関数ポインタとして他の関数に渡します。
通常であれば、f を他の場所で実行する時には変数 a は消滅しているので使用できません。しかし、f がクロージャであればこれを使用できます。
作られたときにあった a をそのまま持って行っているからです。
###追記
タグに無いので適切ではないかもしれませんが、C# の例です。
C#
1/// ボタンが押されたときに実行 2private void button1_Click(object sender, EventArgs e) 3{ 4 // クロージャ取得 5 var mul = createMul(2); 6 7 // mul(3) を実行し、それをデバッグコンソールに書き出す。 8 // 作られたときの 2 が保存されているので、この結果は 6 となる。 9 Debug.WriteLine(mul(3)); 10 11 mul = createMul(5); 12 Debug.WriteLine(mul(3)); // この結果は 15 になる。 13} 14 15// クロージャを作って返すメソッド 16private Func<int, int> createMul(int a) 17{ 18 // f(b) とした時に a * b を返すクロージャを返す 19 return b => a * b; 20}
投稿2016/07/13 22:08
編集2016/07/13 22:38総合スコア28671
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。