小池啓仁 ヒロヒト応援ブログ By はてな

小池啓仁(コイケヒロヒト)の動画など。

小池啓仁 ヒロヒト応援ブログ By はてな

foreachのワーク変数には参照が入る!!

配列変数をforeachで処理するときに、配列変数の要素をワーク変数(下のサンプルでは$value)へ格納しますが、これには、値でなく参照が入ります。


ですので、ワーク変数を編集すると、実は配列変数の要素を編集することになり、思わぬ結果が生じることがあるのです(経験者は語る)。


以下のNo.1では、@Nameの要素に対して、文字列『<br>』が外側のループ毎に一つ多く付加される(想定外)。


これを避けるためには、No.2のように一時変数にsubstr(元の値をコピー)して、その一時変数に対して、文字列『<br>』を付加します。

サンプル No.1

use strict;
use warnings;

print '◆No.1 foreachのワーク変数$valueをそのまま使う', "\n";
my $Name = "";
my @Name = ('aaaa(10)', 'bbbb(11)', 'cccc(12)', 'dddd(13)');
for (my $i = 0; $i < 3; $i++) {
    foreach my $value (@Name) {
        $value =~ s/(^.*)(\(.*$)/$1<br>$2/; # ワーク変数$valueの内容を編集する
        $Name = $Name . "<th>$value</th>";
    }
}
print $Name, "\n";

処理結果 No.1(ループ毎に『<br>』が一つ多く付加されてしまう[異常])

C:\Documents and Settings\koike>perl No1.pl
◆No.1 foreachのワーク変数$valueをそのまま使う
<th>aaaa<br>(10)</th><th>bbbb<br>(11)</th><th>cccc<br>(12)</th><th>dddd<br>(13)<
/th><th>aaaa<br><br>(10)</th><th>bbbb<br><br>(11)</th><th>cccc<br><br>(12)</th><
th>dddd<br><br>(13)</th><th>aaaa<br><br><br>(10)</th><th>bbbb<br><br><br>(11)</t
h><th>cccc<br><br><br>(12)</th><th>dddd<br><br><br>(13)</th>

サンプル No.2

use strict;
use warnings;

print '◆No.2 foreachのワーク変数$valueをsubstrして使う', "\n";
my $Name = "";
my @Name = ('aaaa(10)', 'bbbb(11)', 'cccc(12)', 'dddd(13)');
my $tmp_value;
for (my $i = 0; $i < 3; $i++) {
    foreach my $value (@Name) {
        $tmp_value = substr($value, 0); # ワーク変数内の参照の元の値を一時変数にコピーする
        $tmp_value =~ s/(^.*)(\(.*$)/$1<br>$2/; # 一時変数の内容を編集する
        $Name = $Name . "<th>$tmp_value</th>";
    }
}
print $Name, "\n";

処理結果 No.2(こちらは、ループしても必ず一つのみ付加される[正常])

C:\Documents and Settings\koike>perl No2.pl
◆No.2 foreachのワーク変数$valueをsubstrして使う
<th>aaaa<br>(10)</th><th>bbbb<br>(11)</th><th>cccc<br>(12)</th><th>dddd<br>(13)<
/th><th>aaaa<br>(10)</th><th>bbbb<br>(11)</th><th>cccc<br>(12)</th><th>dddd<br>(
13)</th><th>aaaa<br>(10)</th><th>bbbb<br>(11)</th><th>cccc<br>(12)</th><th>dddd<
br>(13)</th>