local - パッケージ変数を一時的に退避して復元
localを使うと、パッケージ変数を一時的に変更することができます。
local 変数名 = 値;
値が指定されなかった場合は、未定義値が設定されます。
値の保存と復元
localを使って値を代入すると、スコープの終わりで以前の値が復元されます。
our $NUM = 5; { local $NUM = 3; } # ここでは「$NUM」は「元の値」である「5」に戻る
localによって変更されたパッケージ変数は、スコープの最後で復元されます。
初期化を行わなかった場合は、変数の値の初期値は、未定義値になります。
local $NUM;
localは、ourで宣言されたパッケージ変数が対象であって、myで宣言されたレキシカル変数には利用できないことに注意してください。
# コンパイルエラー my $num; local $num;
ただし例外があって、配列の値とハッシュの値には使用することができます。
my @nums = (1, 2, 3); local $nums[1]; my %score = (math => 90, english => 70); local $score{math};
特殊変数に対するlocal
Perlで最もよくlocalを使う場面は「$/」や「%ENV」や「@ARGV」などの、特殊変数に対してです。
localはパッケージ変数を対象としますが、実は特殊変数は、mainというパッケージに属しています。
ですので、特殊変数に対しても、localを使用できます。
local $/; local $ENV{HOME}; local @ARGV;
変数宣言にはmyを使う
Perl 5.0以降のPerlには「my」による変数宣言が導入されていて、lcoalによって変数を宣言する必要性はほとんどなくなっています。ほぼすべての変数宣言は「my」を使うようにしましょう。
# 変数宣言 my $num;
myとlocalの違い
localは、名前の期待に反して、変数宣言ではありません。ダイナミックなスコープを持ちます。
他の言語でいうローカル変数とはPerlにおけるmyを使ったレキシカル変数のことです。
local | my |
---|---|
変数宣言ではない | 変数宣言である |
値を保存・復元する | 変数を宣言する |
ダイナミックスコープを持つ | レキシカルスコープを持つ |
ファイルの内容を一度に読み込む
localを自発的に使う場面は、あまりありませんが、使う場面があります。それは、ファイルの内容を一度に読み込むという処理を記述する場合です。
ファイルの内容を一度に読み込む処理を記述してみます。
my $file = 'a.txt'; open my $fh, '<', $file or die "Can't open $file: $!"; # ファイルの内容を一度に読み込む my $content = do { local $/; <$fh> };
doブロックは最後に評価された値を返すものです。
localによって、ファイルの中での改行を表す特殊変数「$/」を未定義にしています。
これによってファイル入力演算子「<$fh>」が、ファイル全体の内容を返すようにしています。
そして、スコープが終わると「$/」は元の状態に戻ります。
ファイルを一度に読むこむ関数を標準で持たないPerlでは、このようにしてファイル全体の内容を読み込むことがあるということを覚えておきましょう。
localのサンプルプログラム
localを使って、特殊変数を一時的に変更するサンプルです。特殊変数はmainパッケージに属するパッケージ変数です。
{ # 特殊変数$/の一時的な変更 local $/ = undef; } # スコープを抜けると元の値が復元される
localを理解するためのサンプルです。
use strict; use warnings; # localの説明 our $NUM = 1; print "\$NUM = $NUM\n"; # $NUM の完全修飾名は、$main::NUM で、mainパッケージに属する。 # ( Perlでは、どんな変数もグローバル変数にはならない # Perlには、レキシカル変数とパッケージ変数しか存在しない。) print "\$main::NUM = $main::NUM\n"; print "\n"; { # レキシカルスコープの内部で「$NUM」の値を一時的に変更 local $NUM = 2; print "In scope\n"; # 2を出力 print "\$NUM = $NUM\n"; } print "\n"; # 1を出力 print "Out of scope\n"; print "\$NUM = $NUM\n";