Hatena::ブログ(Diary)

西尾泰和のはてなダイアリー

2010-08-12

Perlのスコープがわからない→わかった!

use strict;
use warnings;

sub foo{
    my $x = "static";
    sub bar{
	print $x;
    }
    &bar();
}

&foo();
Variable "$x" will not stay shared at tmp.pl line 7.

むむ、当然参照できると思ったらできなかった。なぜだ?


@miyagawa それはwarning なので参照はできてるはずですよ。staticってprintされてませんか? warning の意味は、2回目以降の呼び出しでは違う変数になるのでclosureではなくなるからです。see perldoc perldiag

ありがとうございます!!警告に目を取られて表示されているのに気づいてませんでした。

tmp$ perl tmp.pl
Variable "$x" will not stay shared at tmp.pl line 8.
statictmp$


@miyagawa perl -e 'sub foo { my $x = 1; sub bar { warn $x++ } bar() } foo() for 1..3' とすると、will not stay shared の意味がわかるかと

tmp$ perl -e 'sub foo { my $x = 1; sub bar { warn $x++ } bar() } foo() for 1..3'
1 at -e line 1.
2 at -e line 1.
3 at -e line 1.

tmp$ perl -e 'sub foo { my $x = 1; my $bar = sub{ warn $x++ }; $bar->() } foo() for 1..3'
1 at -e line 1.
1 at -e line 1.
1 at -e line 1.


my $bar = ...でつくらないと、最初にfooが呼ばれたときに作られたbarが使い続けられてしまうと理解した。my $foo = sub{...}は関数オブジェクトを作ってレキシカルスコープの名前$fooに束縛するわけだが、sub foo{...}構文は作った関数オブジェクトをどこか別のところに束縛するようだ。グローバルスコープではなさそうだったけども、今準備している講義資料の内容から外れるので深追いは避ける。

use strict;
use warnings;

sub foo{
    my $x = "static\n";
    my $bar = sub{
	print $x;
    };
    $bar->();
}

&foo();


続いて動的スコープのデモ。

#use strict;
#use warnings;

sub foo{
    my $bar = sub{
	print $x;
    };
    $bar->();
}

$x = "global\n";
&foo();
{
    local $x = "dynamic\n";
    &foo();
}
&foo();
global
dynamic
global
Connection: close