ここでは、変数の局所化に使う my と local について解説します。どちらも変数を局所化することには違いないのですが、細かな点で違いがあり、これを理解していないと、想定しない結果となってしまいます。しっかりと押さえておきたいポイントです。
- 局所化とは
- my について
- local について
ここでは、変数の局所化に使う my と local について解説します。どちらも変数を局所化することには違いないのですが、細かな点で違いがあり、これを理解していないと、想定しない結果となってしまいます。しっかりと押さえておきたいポイントです。
ここでは、my について解説します。my は、Per5から実装された関数で、Perl4では使えません。Perl4では local のみが使えましたが、Perl5では、my を使うのが一般的ですので、しっかりと理解してください。
まず、言葉を覚えましょう。my を使って定義された変数は、レキシカルスコープ変数 と呼びます。そして、my を使って変数を宣言することをレキシカルスコープ宣言と呼びます。
宣言の仕方は
などです。では、レキシカルスコープ変数の有効範囲は、どこまでかと言うと、次の例を見てください。
1 2 3 4 5 6 7 8 |
$var = 'サブルーチンの外'; print $var; #「サブルーチンの外」が出力される &example; sub example { my $var = 'サブルーチンの中'; print $var; #「サブルーチンの中」が出力される } print $var; #「サブルーチンの外」が出力される |
---|
この場合、2行目で出力される値は「サブルーチンの外」ですね。そして6行目で出力される値は「サブルーチンの中」となります。サブルーチンの中で、$var
のレキシカルスコープ宣言をしているため、新たにメモリー上に値が保持されることになります。もちろん、2行目で定義した $var
の値も保持されたままです。それぞれの $var
は、同じ名前にもかかわらず、変数名も値も、別々に保持されます。つまり、それぞれの $var
は、名前は同じですが、まったく別の変数として処理されます。ただし、5行目のサブルーチン内で定義された $var
の変数名と値は、サブルーチンを抜けた時点で、破棄されてしまいます。
では、8行目では、何か出力されるのでしょうか。上の説明でお分かりかと思いますが、「サブルーチンの外」が出力されるわけです。サブルーチンの外からは、5行目で定義した値は参照できないことに注意してください。
次に、5行目で my を使って宣言しなかった場合には、どうなるでしょうか。
1 2 3 4 5 6 7 8 |
$var = 'サブルーチンの外'; print $var; #「サブルーチンの外」が出力される &example; sub example { $var = 'サブルーチンの中'; print $var; #「サブルーチンの中」が出力される } print $var; #「サブルーチンの中」が出力される |
---|
上記の通り、8行目の値が変わってしまいましたね。5行目で my を使って局所化していなかったため、1行目で代入した値が、5行目で書き換わってしまったのです。そのため、8行目の出力結果も変わってしまったというわけです。意図的にそうしたいのであれば問題ないのですが、そうでなかったら、バグになってしまいますね。
次に、サブルーチンがネスト(入れ子)になったパターンを紹介します。ここで言っているネストとは、サブルーチンの中でサブルーチンを呼び出した場合のことを指しています。
1 2 3 4 5 6 7 8 9 10 11 |
$var = 'サブルーチンの外'; &example; sub example { my $var = 'サブルーチンの中'; print $var; #「サブルーチンの中」が出力される &example2; } sub example2 { print $var; #「サブルーチンの外」が出力される } print $var; #「サブルーチンの外」が出力される |
---|
この例では、4行目でレキシカルスコープ変数として $var を宣言していますので、この $var
の有効範囲は、7行目までとなります。しかし、その手前の6行目でサブルーチン example2 を呼び出していますね。その場合、4行目で宣言された $var は example2 の中でも有効になるのでしょうか。答えは、Noです。9行目で呼び出している $var
は、グローバル変数の $var
で、1行目で宣言されたものなんです。
話が若干それますが、もし、変数をサブルーチンに引き継ぎたい場合には、以下の例のように、引数をを正しく与えてるべきです。
1 2 3 4 5 6 7 8 9 10 11 12 |
$var = 'サブルーチンの外'; &example; sub example { my $var = 'サブルーチンの中'; print $var; #「サブルーチンの中」が出力される &example2($var); } sub example2 { my($var) = @_; print $var; #「サブルーチンの中」が出力される } print $var; #「サブルーチンの外」が出力される |
---|