当たり前のことなのだけど、改めて纏めてみる。レキシカルスコープとパッケージの範囲って全然違うんだなあ。
our と my
#!/usr/bin/perl use strict; use feature qw! say !; package AAA; our $our_var = 123; my $my_var = 567; package DDD; say '$our_var : ' . ( $our_var // "undefined" ); say '$AAA::our_var : ' . ( $AAA::our_var // "undefined" ); say '$DDD::our_var : ' . ( $DDD::our_var // "undefined" ); say '$my_var : ' . ( $my_var // "undefined" ); say '$AAA::my_var : ' . ( $AAA::my_var // "undefined" ); say '$DDD::my_var : ' . ( $DDD::my_var // "undefined" );
$our_var : 123 $AAA::our_var : 123 $DDD::our_var : undefined $my_var : 567 $AAA::my_var : undefined $DDD::my_var : undefined
ourもmyもレキシカルスコープ全体で有効になる。この例の場合、その範囲はスクリプト全体となる。- レキシカルスコープ内では例えパッケージが違っていても参照できる(10, 13 行目)。
ourは変数をパッケージの名前空間に紐付けする。つまり、グローバル変数を作る。myにそのような効果はないのでパッケージ名を付けても参照できない(14 行目)。
our と use vars
our とよく似た機能として use vars プラグマがある。どちらも変数をパッケージの名前空間に紐付けする点では同じだが、our がレキシカルスコープ内で有効になるのに対して、use vars はパッケージ内で有効になる点が異なる。
#!/usr/bin/perl use strict; use feature qw! say !; package AAA; use vars qw! $use_vars_var !; $use_vars_var = 678; our $our_var = 123; package DDD; say $our_var; # これは大丈夫 say $AAA::use_vars_var; # これも大丈夫 say $use_vars_var; # ここでエラー! say $use_vars_var; # ここでエラー!
use vars が無効な範囲でもパッケージ名で修飾すれば参照できる(12 行目)。歴史の古いモジュールなどではよく見かけるが、our の使える今では、あえて使う意味はない。
local と local our
local はグローバル変数にスコープ内でのみ有効な値を与えるときに使われる。
#!/usr/bin/perl
use strict;
use feature qw! say !;
our $var = 123;
{
local $var = 345;
&say_var;
}
&say_var;
sub say_var {
say $main::var // "undefined";
}
345 123
local 文で与えた変更はスコープ内で呼び出された関数でも有効だ。では次のコードだとどうなるか。
#!/usr/bin/perl
use strict;
use feature qw! say !;
{
our $var = 345;
&say_var;
}
&say_var;
sub say_var {
say $main::var // "undefined";
}
345 345
our が有効なのはスコープ内だけであるのに、そこで与えた変更はスコープ外にも波及する。これを避けるために local our を使う。
#!/usr/bin/perl
use strict;
use feature qw! say !;
{
local our $var = 345;
&say_var;
}
&say_var;
sub say_var {
say $main::var // "undefined";
}
345 undefined
これでスコープ内だけで有効なグローバル変数が使えるようになった。一時的に、定数に別の値を与えて関数を呼び出す場合に有効だ。
でも結局……
しかしこのような例は Perl においてさえもレガシーといえる書き方だ。関数の挙動を決めるのにはグローバル定数なんか使わず、素直に引数を与えて呼び出した方がよい。
#!/usr/bin/perl
use strict;
use feature qw! say !;
my $var = 678;
{
my $var = 345;
&say_var( $var );
}
&say_var( $var );
sub say_var {
my $var = shift;
say $var // "undefined";
}
345 678
これだけ書いておいて何だが、結局言えるのは「グローバル変数はトラブルの元。全部 my 使ってレキシカル変数で処理した方がマシ」ってこと。他人のコード読むときは仕方ないけどね。
