あなたの天然記念物
ホーム更新雑談Perl鉄ゲタランドナーコースガイド自転車Linuxリンク経歴連絡先

特殊変数「$_」の更新に注意 (2017.02.12)

背景

何年も前に特殊変数$_の内容が意図通りにならず頭を抱えて対症療法で済ましていました。これが久しぶりに再発したので原因をキチンと調べて再発防止を図ります。

分かったこと(=これまで分かってなかった)

ここに書いてありました。
「$_ はグローバル変数です。」
Perlの組み込み変数 $_ の翻訳 - perldoc.jp

サンプルコード

干支の酉に☆をマークするサブルーチンを2つ書きました。 eto_mark_1は正常、eto_mark_2はforループの$_を上書きしてしまいます。 私の場合、そのサブルーチン内でforループしたケースもあって稀なケースでした。 まあこれで原因と対策が判明しましたから再発しないことでしょう。
#!/usr/bin/perl -w

use utf8;
use strict;
use warnings;
use open IO => ":utf8";

use Encode::Locale;

binmode STDOUT, ":encoding(console_out)";

$| = 1;

my @eto = qw / 未 申 酉 戌 亥 /;
print "ループ前:@eto\n";
for (@eto) {
	print "コール前:$_\n";
	eto_mark_2($_);
	print "コール後:$_\n";
}
print "ループ後:@eto\n";

exit;

sub eto_mark_1 {
	my ($eto) = @_;
	$eto .= "☆" if $eto =~ /酉/;
	print "コール中:$eto\n";
}

sub eto_mark_2 {
	my ($eto) = @_;
	$_ = $eto;
	s/酉/酉☆/;
	$eto = $_;
	print "コール中:$eto\n";
}

実行結果

始めに正常ケースeto_mark_1の結果です。まあ意図通りに☆マークがついてますね。
ループ前:未 申 酉 戌 亥
コール前:未
コール中:未
コール後:未
コール前:申
コール中:申
コール後:申
コール前:酉
コール中:酉☆
コール後:酉
コール前:戌
コール中:戌
コール後:戌
コール前:亥
コール中:亥
コール後:亥
ループ後:未 申 酉 戌 亥
次に失敗ケースeto_mark_2の結果です。 マークを付けた相手はサブルーチンの呼び出し元のforループの配列の要素です。 なのでループ後のリストも酉☆になりました。
ループ前:未 申 酉 戌 亥
コール前:未
コール中:未
コール後:未
コール前:申
コール中:申
コール後:申
コール前:酉
コール中:酉☆
コール後:酉☆
コール前:戌
コール中:戌
コール後:戌
コール前:亥
コール中:亥
コール後:亥
ループ後:未 申 酉☆ 戌 亥

まとめ