続・myとour
ちょっとうまく説明できるかどうかわからないけど挑んでみる。読ませてもらってるbloggerさんのためになるならやってみるだけの価値はあるよね。
最初に。
まずコードは以下のようなもの。
use strict; use warnings; { package foo; my $name = 'foo'; sub get_name { return $name } } my $name = 'main'; print "$name\n"; print foo::get_name(), "\n";
これを実行すると、
foo main
スコープを抜けた後も、&foo::get_name
はスコープ内のレキシカル変数にアクセスできる。
リファレンスカウントを覗こう。
こういうときに役立つのがこれ、[http://search.cpan.org/dist/Devel-Peek/Peek.pm:title=Devel::Peek]
。XSのデバッグに使うようなモジュールなんだけど、これを使うとリファレンスカウントを覗くことが出来る。じゃあやってみよう。
use strict; use warnings; { package foo; use Devel::Peek; my $name = 'foo'; sub get_name { return $name } Dump $name; } my $name = 'main'; print "$name\n"; print foo::get_name(), "\n";
実行結果は以下。
SV = PV(0x27621c) at 0x276144 REFCNT = 2 FLAGS = (PADBUSY,PADMY,POK,pPOK) PV = 0x27f594 "foo"\0 CUR = 3 LEN = 4 main foo
これを見るとわかるけど、リファレンスカウント(REFCNT)が2になってる。$name
という名前と、&foo::get_name
という関数から参照されているからね。ためしにsub get_name
をコメントアウトして実行してみると、
SV = PV(0x27621c) at 0x276144 REFCNT = 1 FLAGS = (PADBUSY,PADMY,POK,pPOK) PV = 0x27f594 "foo"\0 CUR = 3 LEN = 4
リファレンスカウントは1。$name
という名前でのみ参照されるからね。
my
変数とサブルーチンの可視範囲。
my
変数は宣言したあと、存在するレキシカルスコープ内でのみ参照できる。サブルーチンはパッケージに対してグローバルだから、レキシカルスコープの影響は受けない。だからこういう書き方も出来る。
use strict; use warnings; { package foo; my $name = 'foo'; sub get_name { return $name } } my $name = 'main'; print "$name\n"; package foo; print get_name(), "\n";
サブルーチンを定義したパッケージとは別のパッケージから呼び出すときは完全修飾しないといけないけど、もう一度宣言したのと同じパッケージを指定してやれば、サブルーチン名だけで呼び出せる。
今重要なのは、「サブルーチンはパッケージ名で完全修飾してやればどこからでも呼び出せる」ということ。
ごめん、出かけないといけないから続きは帰ってきてから書きます。多分6時過ぎになるかな。出かけてる間に解決したみたい。よかったよかった。いちおう要点だけちょっとだけ書き足しておこう。中途半端なところでとめておいてもアレだし。
- レキシカル変数はスコープを抜けたときに破棄される。
- より正確にはスコープを抜けるとリファレンスカウントが1減る。これが0になった時点で破棄される。
- サブルーチンはパッケージ名で修飾することでどこからでも参照できるグローバルな存在。
- サブルーチンがレキシカル変数を参照しているので、スコープを抜けてもリファレンスカウントが残っている。