読者です 読者をやめる 読者になる 読者になる

スカラーの無名リファレンスでぶつかった謎

perl

あ、リファレンス少しわかったかも?! と思った直後、いや・・やっぱわかってないな・・と思われる事象があったので、ご相談用エントリーです。

最初、@bayashiさんの以下の記事でリファレンスを復習していて、
http://bayashi.net/diary/2012/0428

おお、なるほどなるほど、ああそういうことか・・!
とか色々わかった気になっていたのですが、
それをじゃあ手元で、ある意味一番原理みたいなところかと思われるスカラーのリファレンスで試してみようと思って、以下のようなものを書いてみました。

my $foo = \'sushi'; #スカラーの無名リファレンスを作る
print "1: $$foo\n";

my $bar = $foo; #別のスカラー変数にコピー
$$bar = 'curry'; #コピー先をデリファレンスして中身変更

print "2: $$bar\n"; # curryを期待
print "3: $$foo\n"; # sushiからcurryへの書き換えを期待

しかし実行すると、

Modification of a read-only value attempted at (略) line 9.
1: sushi

てな具合に、最初のプリント文しか出てきません。エラーを見ると、該当行の

$$bar = 'curry'; #コピー先をデリファレンスして中身変更

というところがなんか間違ってるようです。

しかし、これとほとんど同じことを配列やハッシュのリファレンスでやると、@bayashiさんのところでも説明されているとおり、ちゃんと「リファレンスのコピー先で中身を変えるとコピー元の中身も変わる」が再現されます。やってみます。

my $foo_array = ['sushi', 'curry']; #配列の無名リファレンスを作る
print "1: @$foo_array\n";

my $bar_array = $foo_array;
$bar_array->[1] = 'cake'; #デリファレンスして中身を変更
print "2: @$bar_array\n";
print "3: @$foo_array\n"; #元の中身も書き換わってる

print "\n";

my $foo_hash = {lunch => 'sushi'}; #ハッシュの無名リファレンスを作る
print "4: $foo_hash->{lunch}\n";

my $bar_hash = $foo_hash;
$bar_hash->{lunch} = 'curry'; #デリファレンスして中身を変更
print "5: $bar_hash->{lunch}\n";
print "6: $foo_hash->{lunch}\n"; #元の中身も書き換わってる

実行すると、

1: sushi curry
2: sushi cake
3: sushi cake

4: sushi
5: curry
6: curry

どちらもちゃんと、参照先で変更したとおり、元の中身も書き換わってます。

で、さらにはスカラーのリファレンスにしても、無名リファレンスではなくて、先に元となる変数を作ってからリファレンスを作ると、期待どおりに動くようです。やってみます。

my $foo = 'sushi'; #スカラー変数を作って中身を入れる
my $foo_ref = \$foo; #そのリファレンスを作る
print "1: $$foo_ref\n";

my $bar_ref = $foo_ref;
$$bar_ref = 'curry'; #デリファレンスして中身を変更
print "2: $$bar_ref\n";
print "3: $$foo_ref\n"; #元の中身も書き換わってる

実行すると・・

1: sushi
2: curry
3: curry

変わってますね。となると、最初のやつ、どうしてダメなのかがここまでの流れからだと分かりません。
最後のスカラーのやつで、2段構えにすれば期待どおりに動くってことだけ見れば、なるほど無名リファレンスの場合は参照先での変更は参照元に影響しないのか、と単純に納得できますが、その上の配列やハッシュの無名リファレンスの書き換えができてることを見ると、そのようには説明できないわけで。

ということは、単純にスカラーの無名リファレンスだけ、配列やハッシュのそれとは挙動が違うってことなのかなあ〜、とも思ってしまうんですが、それはそれで意味わからないというか。

ということでお分かりになる方、ぜひ教えてください・・!

# Twitterとかでも大丈夫です。-> @note103
# なんだかNHKの『生活笑百科』みたいになってきた・・
バラエティー生活笑百科 - Wikipedia