角括弧でアレイのコピーになる

[@a]という構文が出てきてコレは何なのかamachangに聞いたらアレイのコピーなんだって。

$b = [@a];で@aがコピーされてそれへの参照が$bに入る。@$bと書いてデリファレンスしてやると同じ内容のアレイであることがわかる。

C:\>perl -e "@a = (1,2,3); $b = [@a]; print $b"
ARRAY(0x1001345c)
C:\>perl -e "@a = (1,2,3); $b = [@a]; print @$b"
123

一方 $b = \@a;ならば参照のコピーなのでaを書き換えるとbも変わる。あれ、変わってない…。

C:\>perl -e "@a = (1,2,3); $b = \@a; $a->[1] = 5; print @$b"
123
        • -

解答篇

@aは参照ではなくアレイの実体なので$a->[1]=5;ではなく$a[1]=5;でなければいけない。$aと@aは同じaという名前だけども別もの。$a->[1]=5;を実行したことで新たなアレイが作られその参照が$aに入っている。$aをデリファレンスした@$aと@aに別の物が入っていることが下のコードで観測できる。

C:\>perl -e "@a = (1,2,3); $b = \@a; $a->[1] = 5; print @$a;"
5
C:\>perl -e "@a = (1,2,3); $b = \@a; $a->[1] = 5; print @a;"
123

改めてきちんと$a[1]=5;と書くと$b = \@aは@aへのリファレンスが$bに入っているだけだけど、[@a]ではコピーされているということがわかる。

C:\>perl -e "@a = (1,2,3); $b = \@a; $a[1]=5; print @$b;"
153
C:\>perl -e "@a = (1,2,3); $b = [@a]; $a[1]=5; print @$b;"
123

ちなみに$bはリファレンスなので$b->[5]とやってやらないといけない。$b[5]と書いてしまうと上とは逆に$bが指しているアレイとは別のアレイ@bが新たに作られてしまう。

C:\>perl -e "@a = (1,2,3); $b = \@a; $b->[1]=5; print @a;"
153
C:\>perl -e "@a = (1,2,3); $b = \@a; $b[1]=5; print @a;"
123
C:\>perl -e "@a = (1,2,3); $b = \@a; @$b[1]=5; print @a;"
153

まとめ:Perl初心者がPerlを学ぶ上でまず最初に覚えるべき命令はuse strictとuse warningsである。

C:\>perl -e "use strict; use warnings; my @a = (1,2,3); $b = \@a; $a->[1] = 5; print @$b;"
Name "main::a" used only once: possible typo at -e line 1.
123