当たり前のことなのだけど、改めて纏めてみる。レキシカルスコープとパッケージの範囲って全然違うんだなあ。
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
使ってレキシカル変数で処理した方がマシ」ってこと。他人のコード読むときは仕方ないけどね。