続・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になった時点で破棄される。
  • サブルーチンはパッケージ名で修飾することでどこからでも参照できるグローバルな存在。
  • サブルーチンがレキシカル変数を参照しているので、スコープを抜けてもリファレンスカウントが残っている。