2012-04-03

Perl - PACKAGEはブロックスコープじゃない

あまり使わないかもしれませんが、1つのファイルに複数の PACKAGE を書く場合注意が必要かなと。
use strict;
use warnings;

package FOO;
my $hoge = "madoka";

package BAR;
my $moge = "homura";

package BAZ;
print "\$FOO::hoge : $FOO::hoge \n";
print "\$hoge      : $hoge \n";
print "\$BAR::moge : $BAR::moge \n";
print "\$moge      : $moge \n";

------------------
実行結果
$FOO::hoge :        # エラー
$hoge      : madoka # 期待と違ってエラーじゃない
$BAR::moge :        # エラー
$moge      : homura # 期待と違ってエラーじゃない

Name "BAR::moge" used only once: possible typo at - line 12.
Name "FOO::hoge" used only once: possible typo at - line 10.
この場合 $hoge も $moge もレキシカル変数なので
外から見えないことを期待しましたが、なぜか見えます。

では、次の場合はどうでしょう?
use strict;
use warnings;

package FOO;
my $hoge = "madoka";

package BAR;
my $moge = "homura";

package BAZ;
my $hoge = "mami";
my $moge = "sayaka";

------------------
実行結果
"my" variable $hoge masks earlier declaration in same scope at - line 11.
"my" variable $moge masks earlier declaration in same scope at - line 12.
「$hoge も $moge も同じスコープで既に使われてるよ」と怒られます。
PACKAGE が違ってもレキシカル変数は同じスコープみたいです。

これはこれで不便なので期待通りに動かすには次のようにします。
package FOO;
{
    my $hoge = "madoka";
}
もしくは
{
    package FOO;
    my $hoge = "madoka";
}
このように明示的にブロックで囲みます。
これを踏まえて書き直すと
use strict;
use warnings;

package FOO;
{
    my $hoge = "madoka";
    print "\$hoge : $hoge \n\n";
}
package BAR;
{
    my $moge = "homura";
    print "\$moge : $moge \n\n";
}
package BAZ;
{
    my $hoge = "mami";
    my $moge = "sayaka";

    print "\$hoge : $hoge \n";
    print "\$moge : $moge \n";
}

------------------
実行結果
$hoge : madoka 

$moge : homura 

$hoge : mami 
$moge : sayaka 
めでたし、めでたし。


- 追記 -
perlのドキュメントに書いてありました。
perlmod - Perl のモジュール (パッケージとシンボルテーブル) 【perldoc.jp】

パッケージ文は(local() を使った)動的変数にのみ効果を持ちますが、
my() によって生成されたレキシカル変数には影響しません。

0 コメント:

コメントを投稿