• ベストアンサー

whileの$_とforeachの$_の関係

以下のコードにおけるwhileとforeachでの$_の使いかたについて教えてください。 my @foos = qw( a b ); sub foo1 {   open FH, "foo.txt";   while (<FH>) {     chomp;     print "$_";   } #  while (my $x = <FH>) { #    chomp $x; #    print "$x"; #  }      print "\n"; } sub foo2 {   foreach (@foos) {     print "<$_>";     foo1();   }   print "\n"; } foo2(); foo2(); このコードと同じディレクトリに以下のような内容のfoo.txtをおいて実行します。 x y すると、以下のような結果が得られました。 <a>xy <b>xy <>xy <>xy 一回目のfoo2で@foosの内容が消えてしまいます。一方、コメントアウトしてあるようにwhileに変数($x)を使うと期待したとおりの結果が出ます。なぜ、このような結果になるのでしょうか。ご存知の方がいらっしゃったら教えてください。宜しくお願いします。ちなみに、WinXP + ActivePerl(v5.8.6)で試しました。

質問者が選んだベストアンサー

  • ベストアンサー
  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.2

簡単に言うと $_ をfoo1 とfoo2 で使っている為です。 こういうことがあるので 関数の中では使う変数はできるだけ局所的な使い方をするのがよろしいです。 最初の foreach(@foos){ } の中で$_ は、配列の中身のコピーではなくて、配列の要素そのものを指しているので、$_ への変更は直接@foosへの変更になってしまうので注意が必要です(この動作はこの動作で便利なものなんですが・) なので、 foreach my $x (@foos) { print "<$x>"; foo1(); } のようにすれば良かったのかもしれません。 また、 sub foo1{ local $_; … } のようにすれば、 foo1 で(foo2で使っていても)安心して$_ を使うことができます。

kary
質問者

お礼

whileの終了条件のundefが@foosに代入されていたのでしょうね。$_がグローバル変数であることと、$_を変更すると元のデータが変更されることを見落としていました。ご回答、ありがとうございました。

すると、全ての回答が全文表示されます。

その他の回答 (1)

  • hara_peko
  • ベストアンサー率28% (11/38)
回答No.1

ご指摘のように他のループ変数に入れるか、もしくは sub foo1 {   open FH, "foo.txt";   local $_;#明示的にローカル化する   while (<FH>) {     chomp;     print "$_";   }   print "\n"; } とする必要があります。参考URLの I/O Operators の項をご覧下さい。

参考URL:
http://perldoc.jp/docs/perl/5.6.1/perlop.pod
kary
質問者

お礼

localで解決しました。$_を使ったほうが正規表現等の引数を省略できて便利なことも多いので、localを用いた方法を教えていただいて勉強になりました。ありがとうございました。

すると、全ての回答が全文表示されます。

関連するQ&A