- Perl ›
- スコープ
Perlのスコープについて理解しよう
Perlのスコープについて理解を深めましょう。この記事はstrictプラグマを有効にした前提で書いていますので、ソースコードの先頭には普段どおり以下のように書いてくださいね。
use strict; use warnings;
スコープの作成
Perlのスコープは「{」で始まり「}」で終わります。
{ # スコープ }
スコープの意味
レキシカル変数
スコープの中で宣言されたレキシカル変数(myで宣言された変数)は、そのスコープ内でしか参照することができません。また変数に含まれる値はスコープが終わった時点で解放されます。
{ my $num = 1; # 参照できる print $num; } # この位置では参照できない print $num;
パッケージ変数
スコープの内部で宣言されたパッケージ変数(ourで宣言された変数)は、そのスコープの中では部分名で参照できます。スコープの外から参照するには完全修飾名を使用する必要があります。
package Foo; { our $NUM = 1; # 部分名で参照できる print $NUM; } # 部分名では参照できない print $NUM; # 完全修飾名で参照できる print $Foo::NUM;
パッケージ変数は一度作成されればプログラムの最後まで存在し、プログラムのどの位置からでも完全修飾名で参照できるということを覚えておきましょう。
localで変更されたパッケージ変数
localを使うとパッケージ変数を一時的に変更することができます。この変更された値は、スコープの最後で元に戻ります。
package Foo; our $NUM = 1; { local $NUM = 2; # 2が出力される print $NUM; } # この位置では1に戻る print $NUM;
localは、パッケージ変数の値の一時的な変更にだけ利用して、昔のように変数宣言には使わないようにしましょう。
サブルーチン
Perlのサブルーチンはスコープの影響を受けません。
{ sub foo { ... } # 呼び出しが可能 foo(); } # 呼び出しが可能 foo();
サブルーチンは定義された時点で、シンボルテーブルと呼ばれるものに登録され、プログラムのすべての位置から呼び出せるようになります。
サブルーチンにスコープを持たせたい場合は、無名サブルーチン(これはサブルーチンのリファレンス)をレキシカル変数に代入します。
{ my $foo = sub { ... }; # 呼び出しが可能 $foo->(); } # この位置らからは呼び出すことができない $foo->();
スコープの終わりで$fooに代入されているサブルーチンのリファレンスが解放されます。サブルーチン自体が解放されるわけではないということに注意しましょう。sub { ...}は、コンパイルの時点で、解析されてメモリ上に配置されます。
if文やwhile文におけるスコープ
if文やwhile文などで利用される「{}」もスコープです。Perlではありとあらゆる構文で使用される「{}」がスコープになります。この点では一貫しており、他の言語と比較してとてもわかりやすいものになっています。
if (条件) { # スコープ } while (条件) { # スコープ } eval { # スコープ }; sub { # スコープ }
(参考)eval
またファイルもひとつのスコープを持ちます。
use strict; use warnings; # 処理
上記は以下のようにファイルの先頭と終わりが「{」と「}」で囲まれているものと考えることができます。
{ use strict; use warnings; # 処理 }
特殊な位置で宣言されたレキシカル変数
スコープの内部では宣言されてはいないけれども、スコープを持つ場合がいくつかあります。
ifの条件部
ifの条件部で宣言されたレキシカル変数は、ifのスコープを持ちます。
if (my $num = 1) { # 参照できる print $num; } # この位置では参照できない print $num;
後置されるifについてはそもそもスコープがないので、スコープを持ちません。
文 if my $num = 1; # 参照することができる print $num;
unless文やwhile文についても同じです。
# unless unless (my $num = 1) { # 参照できる print $num; } # 参照できない print $num;
# while while (my $num = 1) { # 参照できる print $num; } # 参照できない print $num;
forの条件部
forの条件部で宣言されたレキシカル変数はforのスコープを持ちます。
for (my $i = 0; $i < @nums; $i++) { # 参照できる print $i; } # 参照できない print $i;
forの変数の代入部
forの変数の代入部で宣言されたレキシカル変数はforのスコープを持ちます。
for my $num (@nums) { # 参照できる print $num; } # 参照できない print $num;
終わりに
これだけ覚えておけばPerlのスコープで困ることはないでしょう。Perlのスコープは直感的でわかりやすいものだということがわかると思います。これはPerlのプログラムの構造を見やすいものにするのにとても役立っています。