Perlでは、foreachループを使用すると、配列の要素を便利に繰り返すことができ、ループ変数はデフォルトで($_、または明示的に指定された)参照として配列の要素を指すため、値をコピーしません。
例:
my @arr = (1, 2, 3); foreach my $x (@arr) { $x *= 2; } # @arrは(2, 4, 6)となる — 要素が変更されました!
値のコピーを取得するには(オリジナルの要素への参照ではなく)、変数に明示的に代入する必要があります:
foreach my $x ( @arr ) { # $xは要素への参照 ... } # ↓↓↓↓ foreach (@arr) { my $copy = $_; ... } # $copyはコピー、$_は要素への参照
複数の入れ子のforeachループで同じ変数を使用しない方が良いでしょう。そうしないと、予期しない副作用が発生する可能性があります。
foreachループの変数は独立したコピーであり、ループ本体の中で安全に変更できますか?
一般的に "はい、ループは自動的に変数を作成するので、自由に変更できます。" と答えます。
正しい答え:
Perlでは、デフォルトのループ変数(例えば、foreach $var (@arr))は、配列の要素への**エイリアス(参照)**です。ループ変数を変更すると、オリジナルの要素も変更されます!
一時的なコピーを変更するには、ループの内部で明示的に代入してください:
foreach my $elem (@arr) { my $t = $elem; $t++; # コピーだけで、オリジナルの配列は変更されません }
歴史
歴史 1
レコードをフィルタリングするタスクで、プログラマーはループ変数を変更したが、オリジナルのデータを変更していることに気付いていませんでした。その結果、次の計算は変更された配列に従って行われ、要素の合計が正しく計算されませんでした。このエラーは、リファレンスサンプルと比較したときにのみ発生しました。
歴史 2
内部のforeachで同じ変数($item)を使用しました。内部ループの変数が外部の状態を上書きし、最初の走行の結果が失われ、配列の一部が不正な値になりました。
歴史 3
ハッシュへの参照の配列をforeachで繰り返し、それぞれのループでループ変数に新しい値が割り当てられました。その結果、参照が「壊れ」、参照値の代わりにスカラーが配置され、次の処理ステージが型エラーで失敗しました。