our, my, local

ourはグローバル変数の宣言、localは一時的にグローバル変数を上書きするものと理解した。いいのかな?

localとdo->();

our $foo = 0;

do {  # ... (1)
    local $foo = 1;
    do { print "$foo\n" }; # 1
    sub { print "$foo\n" } # 0
}->();
my と local のサンプル - IT戦記

の意味がよくわからなかったけど、外側のdo{}の返り値がsub { print "$foo\n" }のリファレンスでそれを->()で実行しているのだとわかった。
よく読んだらそのとおり書いてある><

sub は値(リファレンス)として返され、すぐに実行されます。

my と local のサンプル - IT戦記

で、localは一時的にグローバル変数を上書きするものだから変数の呼び出されるタイミングが大事になる。
この場合だと内側のdo{}が呼び出されるのは外側のdo{}の中だが、sub{}が実際に呼び出されるのは外側のdo{}を抜けた後になってしまう。sub{}が呼び出されるときにはlocalの効果はなくなっている。だからour $foo = 1;の1our $foo = 0;の0がprintされる。

次のように書くと、内側のdo{}もsub{}もlocalで上書きされた$fooを使う。sub{}が外側のdo{}の中で使われているので、localによる一時的な書き換えが有効になっている。

do {  # ... (1)
    local $foo = 1;
    do { print "$foo\n" }; # 1
    sub { print "$foo\n" }->(); # 1
};

myの場合

do {  # ... (2)
    my $foo = 1;
    do { print "$foo\n" }; # 1
    sub { print "$foo\n" } # 1
}->();
my と local のサンプル - IT戦記

外側のdo{}の中では$fooはグローバル変数の$fooではないと決めたので、内側のdo{}でもsub{}でも$fooはここで代入された1になる。

do {  # ... (2)
    my $bar = 1;
    do { print "$bar\n" }; # 1
    sub { print "$bar\n" } # 1
}->();
my と local のサンプル - IT戦記

と書いたのと同じこと。

結局は

our 名前をソース上のスコープに限定. local 値をスタック上のスコープに限定. my 名前と値の両方をソース上のスコープに限定

local と my - IT戦記

に行き着く気がする。

あと

サブルーチン定義の sub func {}、無名関数 sub {} については、関数を宣言した時ではなく、関数を呼び出した時にブロックのスコープを持つと解釈すればOKです。

http://d.hatena.ne.jp/TAKESAKO/20080110/1199969773

も忘れないように。