-
Notifications
You must be signed in to change notification settings - Fork 7
Closure
Silica edited this page Sep 4, 2012
·
8 revisions
#Closure int x = 1; c = $(){print(x);}; c(); // 1
##$演算子 CLOSURE命令
$は単体の演算子である
ローカル変数への参照を無名関数に渡したに過ぎない
$a
とすればローカル変数aに対し、ローカル変数への参照をメンバとして登録する
int x = 1;
$a;
print(a.x); // 1
ここでいう参照とはスクリプト内の参照型ではなく
内部的な機能による変数の共有である
外のxとa.xは全く同じ変数として動作する
尚、参照ではなくコピーを渡すことも出来る
コンパイルオプションで切り替える
##注意点
クロージャ命令は命令を実行した時のローカル変数を、対象のメンバとして登録する
対象のメンバというのはつまり、内側から見ればstatic変数のことなので
クロージャを重ねた場合には伝播しない
list = (1,2,3);
int total = 0;
foreach(list, $(x){
total += x;
});
print(total); // 6
これはいい
list = (1,2,3),(4,5,6),(7,8,9);
int total = 0;
foreach(list, $(x){
// ここからはstatic変数としてtotalを参照する事が出来るが
foreach(x, $(y){
// static変数は渡されない為にここからは見えなくなっている
total += y; // よってこのtotalは外から渡されてきたtotalではなく
// この中で新たに作られたローカル変数である
});
});
print(total); // 0
回避するには一旦ローカル変数に渡す必要がある
list = (1,2,3),(4,5,6),(7,8,9);
int total = 0;
foreach(list, $(x){
ref t = total;
foreach(x, $(y){
t += y;
});
});
print(total); // 45
変える(static変数も渡す様にする)かもしれない
また別種の問題として、代入の際にコピーを作る問題もある
int x = 1;
c = $(y){x = y;};
c(10);
print(x); // 1
何故か
(y){x = y;}
という関数リテラルにxを渡す
仮にこれにanonymousという名前を仮定して考えれば
anonymous = (y){x = y;};
anonymous.x = &x; // 厳密に言えば(内部)参照を渡すのだが
この様な動作と同じである
ここで次にc = anonymous;
という操作をしていることを考えれば答えは自ずと見えてくる.
anonymousはメンバごとコピーされる、その際に内部参照は消えて値のみがコピーされる.
回避するにはref c = $(y){x = y;};
とするか、
クロージャを作るタイミングをcにコピーした後にする、つまり
c = (y){x = y;};
$c;
// または
$(c = (y){x = y;});
foreachに渡す場合は気にしなくてよい(自動的に参照を渡す)が
まあそのうち考える