Perlの勘所2 スコープ

今回は変数・スコープ周りについて説明する。
 

変数のスコープを理解する

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のスコープは馴染み深いはずだ。myは,最近のプログラミング言語(C,Java,PHPなど)で実装されている変数のスコープとほとんど同じである。しかし,上記の通り,同一のファイルに複数のパッケージが記載されている場合は,myはパッケージスコープを超えてしまう。これを防ぐには,以下のようにパッケージに{}ブロックを付けて記述する。このようにすることでmyのスコープをパッケージ内に限定することができる。
 

use strict;
use warnings;
package AAA;
{
    my $hoge = 'サブルーチンの外'; #変数をmyで宣言
    print $hoge; #「サブルーチンの外」が出力される
}
package BBB;
{
    print $hoge; #←ここで変数を参照するとエラー
}

 

ourの使い方

ourはレキシカルスコープを持つ。myとの大きな違いとして,以下の2つがある。

  1. スコープを抜けて、もう一度同じスコープに入ってきたときに、前の値を保持している
  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はこのような特徴を持つ。
 

package foo;
{
    our $hoge = 'foo';
}

package bar;
{
    print $foo::hoge; #パッケージ名前空間を利用して参照することができる
}

 
ourでは,$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について。

Article written by

コメントを残す