our変数の動作とか
Perlのmy, local, ourの違いについて,はてブ方面で盛り上がっていましたので,私も5年ぶりぐらいにPerlを触ってみましたが,ourの検証でのっけからはまりました.
まず,「ourはレキシカル変数だ」と思って,次のようなコードを書きました.
#!/usr/local/bin/perl use strict; use warnings; package Mypackage; our($foo) = 'our in toplevel'; sub bar { sub { $foo .= '!'; print $foo, "\n" } } my $closure; { my($foo) = 'my in bare block'; $closure = bar(); $closure->(); } $closure->(); print $foo, "\n";
これはok.次のように,期待通りに動きます.
% ./lexical1.pl our in toplevel! our in toplevel!! our in toplevel!!
ここで,無名ブロック(クロージャ)の中のmyをlocalに変更してみる.動作に支障はないはず.
#!/usr/local/bin/perl use strict; use warnings; package Mypackage; our($foo) = 'our in toplevel'; sub bar { sub { $foo .= '!'; print $foo, "\n" } } my $closure; { local($foo) = 'local in bare block'; # 変更 $closure = bar(); $closure->(); } $closure->(); print $foo, "\n";
実行結果
% ./lexical2.pl local in bare block! our in toplevel! our in toplevel!
あれ? クロージャの中の$fooがダイナミックスコープ*1になってる.
うーん.これって,our($foo)の,"$foo"という変数名が,local($foo)のところで上書き(シャドウ化)されたってこと? それで,bar()の中に着いた段階では,レキシカル変数であるはずのour($foo)は全然見えないから,変数の束縛も行われなかったってこと?
それならば,と,さらに1行追加.
#!/usr/local/bin/perl use strict; use warnings; package Mypackage; our($foo) = 'our in toplevel'; sub bar { my($foo) = 'my in bar'; # 追加 ...(1) sub { $foo .= '!'; print $foo, "\n" } } my $closure; { local($foo) = 'local in bare block'; $closure = bar(); $closure->(); } $closure->(); print $foo, "\n";
こちらは,以下のように期待通りの結果.しかし,トップレベルのour($foo)が参照できないことは変わらないので全然うれしくない.
% ./lexical3.pl my in bar! my in bar!! our in toplevel
(1) のところで,our($foo)をどうにか参照できないか,と,my($foo) = $Mypackage::fooとか,苦し紛れにlocal($foo) = $fooとかしてみるが,いずれもlocal($foo)がしゃしゃり出てきて全然だめ.
Perlって難しいなぁ.
*1:この日記を書いた時点では,このような動きを何と呼ぶのかわからなかったのだが,shallow bindingと呼ぶのが正しいらしい.