ishiducaの日記 このページをアンテナに追加 RSSフィード

2009-06-13

[][]localで小細工するメモ 18:43 localで小細工するメモ - ishiducaの日記 を含むブックマーク はてなブックマーク - localで小細工するメモ - ishiducaの日記 localで小細工するメモ - ishiducaの日記 のブックマークコメント

決まったファイル(この場合、error.log)を読み込んで処理する(この例だと、print)場合に、関数定義したとして、こんなスクリプトを書いたとする

print_file.pl

#!/usr/bin/perl -w
use strict;
my $log = 'error.log';

&print_file();
exit 0;

sub print_file{
	open my $fh, "<", $log or die "can not open $log";
	while( <$fh> ){
		print $_;
	}
	close $fh;
}

この例だと、$logに設定した error.log 以外は処理できないけど、一時的に別のファイルも処理したくなったとすると、このスクリプトだとうまくない。定義した print_file 関数で読み込むファイル名を引数に指定できるようにしておくのが現実的だけど、小細工したい時に local宣言でごまかせたのでメモ。

our宣言とlocal宣言をセットで

print_file_use_local.pl

#!/usr/bin/perl -w
use strict;
our $log = 'error.log'; #  my -> our

# 一時的な処理
{
	local $log = './archive/2009/06/error.log';
	&print_file();
}

&print_file();

exit 0;

sub print_file{
    ...
}

忘れがちなのが、「my $log = ...」を「our $log = ...」に直すところ。my のままだと、レキシカル変数はローカライズできないよって「Can't localize lexical variable $log at print_file_use_local.pl line xx」なエラーを吐く。

my宣言の罠

また、3行目の「our」と7行目の「local」を「my」に直すとエラーは吐かないけど、11行目で実行した際、7行目で指定した$logのままファイルを読み込んでしまう致命的な事態になってしまう。

print_file_use_my.pl

#!/usr/bin/perl -w
use strict;
my $log = 'error.log';

# 一時的な処理
{
	my $log = './archive/2009/06/error.log';
	&print_file();
}

# この時点で $log は error.log なんだけど
# ブロック内で宣言した ./archive/2009/06/error.log が
# print_file で保持されたままになっている
# これってクロージャってやつ?
&print_file();

exit 0;

sub print_file{
    ...
}

現実的なら、サブルーチンのprint_fileを直す方(引数にファイル名を使うようにする)がベターなんだろうか

sub print_file{
	# &print_file($log);
	my $log_file = shift;
	open my $fh, "<", $log_file or die "can not open $log_file";
	while( <$fh> ){
		print $_;
	}
	close $fh;	
}
トラックバック - http://perl.g.hatena.ne.jp/ishiduca/20090613

2008-11-06

[][][]localを使おうとして怒られた 16:42 localを使おうとして怒られた - ishiducaの日記 を含むブックマーク はてなブックマーク - localを使おうとして怒られた - ishiducaの日記 localを使おうとして怒られた - ishiducaの日記 のブックマークコメント

use strict;
my $str = 'GROBAL';
&PUT();
sub PUT{
    local $str = 'local';
    print $str."¥n";
}
print $str; 

ってやったら、"Can't localize lexical variable $str at - line 5." って怒られた。my を使っちゃいけないらしい。んな訳で

str = 'GROBAL';
&example();
sub example{
    local $str = 'local';
    print $str."¥n";
}
print $str;

結果

local
GROBAL

成功


追記(2009.05.10)

「local」はサブルーチンの中で、グローバル変数の中身を一時的にどこかへ移動して、その代わりに別の値を使う。サブルーチンから抜けると、元の値に戻すものでした。(今更...)

なので、この書き方の方がいいんだろうね

#!/usr/bin/perl -wl
use strict;
our $str ='GROBAL'; # our宣言で、グローバル変数に設定
&example();
sub example{
    local $str = 'local'; # local宣言して、グローバル変数の値を一時的に退避
    print $str;
}    
print $str;
exit 0;
トラックバック - http://perl.g.hatena.ne.jp/ishiduca/20081106