レキシカル変数の宣言場所より前で、その変数を使った関数を呼ばないようにしよう
タイトルだけで伝え終わった感満載。そして多分常識。
use strict; use warnings; use Data::Dumper;sub p {warn Dumper shift;my @c = caller;print STDERR " at $c[1]:$c[2]\n\n"} my $str = 'foo_hoge'; p 'matched' if matched($str); my @list = qw/hoge huga/; sub matched { my $target = shift; for my $l (@list) { return 1 if $target =~ m/$l/; } return 0; }
これを実行したらどうなるのか。
- 期待した動作
- 'matched' とwarnされる
- 現実
- 華麗にスルー
現実は厳しい。
どうすべきか
my @list = qw/hoge huga/; # 先に宣言してやろう my $str = 'foo_hoge'; p 'matched' if matched($str); sub matched { my $target = shift; for my $l (@list) { return 1 if $target =~ m/$l/; } return 0; }
とまあ、タイトル通りにすればいい。
% perl method_place.pl $VAR1 = 'matched'; at method_place.pl:8
おまけのような
じゃあmatch関数の中で、@listをdumpしたらどーなるのかと。
my $str = 'foo_hoge'; p 'matched' if matched($str); my @list = qw/hoge huga/; sub matched { p \@list; my $target = shift; for my $l (@list) { return 1 if $target =~ m/$l/; } return 0; }
% perl method_place.pl $VAR1 = []; at method_place.pl:10
なんと空っぽ。一応、配列としては認識されている。
じゃあ、期待通りの動作をするパターンで試してみると
my @list = qw/hoge huga/; my $str = 'foo_hoge'; p 'matched' if matched($str); sub matched { p \@list; my $target = shift; for my $l (@list) { return 1 if $target =~ m/$l/; } return 0; }
% perl method_place.pl $VAR1 = [ 'hoge', 'huga' ]; at method_place.pl:11 $VAR1 = 'matched'; at method_place.pl:8
値が入った。
教訓
既に使われているコードだからって正しく動いてるとは限らないということを肝に銘じましょう。