今回は変数・スコープ周りについて説明する。
変数のスコープを理解する
Perl言語の変数のスコープには,myとourとlocalの3つがある。基本的に変数のスコープにはmyを使用する。
myの使い方
myはレキシカルスコープと呼ばれるスコープを持つ。単語からでは、どういうスコープを持つのか想像しにくいのが厄介だが,他のサイトでは以下のように説明されていた。
myは、レキシカルスコープで、他言語で言えば、ブロック内のローカル変数のように振舞います。
構文上、ブロックを抜けると、宣言した変数のスコープが終了します。
宣言後、スコープから抜けるまで、他の関数やブロックから、その変数は見えません。
以下にmyの使い方をコードで示す。
use strict;use warnings;package AAA;my $hoge = 'サブルーチンの外'; #変数をmyで宣言print $hoge; #「サブルーチンの外」が出力される&example; #exampleサブルーチン呼び出しsub example { my $fuga = 'サブルーチンの中; #変数をmyで宣言 print $hoge; #「サブルーチンの外」が出力される print $fuga; #「サブルーチンの中」が出力される}print $hoge; #「サブルーチンの外」が出力されるprint $fuga; #←ここで変数を参照するとエラーpackage BBB;print $hoge; #「サブルーチンの外」が出力される
myは,最近のプログラミング言語(C,Java,PHPなど)で実装されている変数のスコープとほとんど同じである。しかし,上記の通り,同一のファイルに複数のパッケージが記載されている場合はmyはパッケージスコープを超えてしまう。これを防ぐには以下のようにパッケージに{}ブロックを付けて記述する。このようにすることでmyのスコープをパッケージ内に限定することができる。
use strict;use warnings;package AAA;{ my $hoge = 'サブルーチンの外'; print $hoge; #「サブルーチンの外」が出力される}package BBB;{ print $hoge; #←ここで変数を参照するとエラー}
ourの使い方
ourはレキシカルスコープを持つ。myとの大きな違いとして,以下の2点がある。
- スコープを抜けて,もう一度同じスコープに入ってきたときに前の値を保持している
- パッケージ名前空間を利用できる
以下にourの使い方をコードで示す。
use strict;use warnings;package foo;my $hoge = 'サブルーチンの外';print $hoge; #「サブルーチンの外」が出力される&example; #1度目のサブルーチン実行 print文で「サブルーチンの中」が出力されるsub example { our $hoge; BEGIN { #BEGINは一度目の呼び出しに限り実行される $hoge = 'サブルーチンの中'; } print $hoge;}print $hoge; #「サブルーチンの外」が出力される$hoge = 'サブルーチンの外';&example; #2度目のサブルーチン実行 print文で「サブルーチンの中」が出力される
上記では,一度サブルーチンのスコープを抜けて,もう一度同じサブルーチンのスコープに入ってきたときに前の値を保持している。ourはこのような特徴を持つ。
更にourでは,$foo::hogeのようにパッケージ名前空間を利用して変数を参照することができる。
package foo;{ our $hoge = 'foo';}package bar;{ print $foo::hoge; #パッケージ名前空間を利用して参照することができる}
localの使い方
localは,ダイナミックスコープを持つ。ダイナミックスコープとは,文字通り動的なスコープのことで,変数のスコープがその宣言を含むブロックに限定されないことを指す。localは,サブルーチンのスコープ内でのみ有効な値を定義することができ,localを宣言したサブルーチンから呼び出したサブルーチンでも同じ値が共有される。
以下にlocalの使い方をコードで示す。
use strict;use warnings;$var1 = 'サブルーチンの外';print $var1; #「サブルーチンの外」が出力される&example1; #サブルーチン実行sub example1 { local $var1 = 'サブルーチンの中'; #localはサブルーチン内でのみ有効 print $var1; #「サブルーチンの中」が出力される &example2; #サブルーチン実行}print $var1; #「サブルーチンの外」が出力されるsub example2 { print $var1; #「サブルーチンの中」が出力される}
上記のように,localはサブルーチンを跨いだ呼び出しを行った場合,値が共有される。また,localを使用することでグローバル変数とローカル変数を視覚的に区別することが容易になり,クラス内の見通しが良くなるという恩恵も得られる。
まとめ
変数宣言には基本的にmyを使用する。グローバル変数的に使用したい変数にはourを使用する。localはサブルーチンの中でのみ使用することができるが,myでも代替することは可能である。ourやlocalを使用することに抵抗がある場合は,無理して使わなくてもよい。Perlのスローガンに「やり方はひとつじゃない」とある通り,ユーザはPerlに用意された様々な方法の中から,自分に合った方法を選ぶことが出来る。
参考
my と local どう違う? – futomi’s CGI Cafe
Perlのour – Perlのourについて。