リファレンスの説明


(1)リファレンスとは

普通の変数に値を代入するとイメージとしては以下のような状態になります。

Perlのコード
$a = 100;

イメージ($aという名前の箱に100が入っている)
   ┌──┐
$a │100 │
   └──┘

参照の場合は値ではなく、値のある場所を示すものが入ります。

Perlのコード
$b = \$a;

イメージ($bは$aを参照している)
   ┌──┐
$a │100 │
   └──┘
     ↑
$b ─┘

上記のように参照する場合は参照したい変数の前に\を付けます。
この状態で$bの値を表示してもSCALAR(0x1832660) というような
よく分からない値が返ってきます。

$bが参照しているものの内容を知りたい場合には以下のように$を付けます。
print ${$b}, "\n";
省略して以下のように書くこともできます。
print $$b, "\n";

この状態で$aの内容を変更すると以下のようになります。

Perlのコード
$a = 200;

イメージ($aが200になった)
   ┌──┐
$a │200 │
   └──┘
     ↑
$b ─┘

実際に
print $$b, "\n";
と実行すると 200 と表示されます。

どういう場合に使うのかというと、関数の引数の値を変えたい時に使えます。

sub add_bracket {
    my $val = shift;
    $$val = "[$$val]";
}

my $str = "abc";
add_bracket(\$str);
print $str, "\n";

これぐらいだとあまり嬉しくないのですが、配列やハッシュの参照を
使えるようになるといろいろと嬉しいことがあります。
(2)配列のリファレンスについて

まずは普通の配列。

Perlのコード
@a = (1, 2);

イメージ
   ┌──┬──┐
@a │  1 │  2 │
   └──┴──┘

配列のリファレンス。

Perlのコード
$b = \@a;

イメージ($bは@aを参照している)
   ┌──┬──┐
@a │  1 │  2 │
   └──┴──┘
     ↑
$b ─┘

配列の場合も参照したい変数の前に\を付けます。参照先が配列になっても
リファレンスを格納する変数はスカラーになります。

内容を知りたい場合には$を付けます。
print ${$b}[1], "\n";
省略して以下のようにも書けます。
print $$b[1], "\n";

さらに別の書き方として
print $b->[1], "\n";
と書くこともできます。私はこの書き方を使っています。

配列全体を参照する場合は@をつけます。
foreach (@{$b}) {
    print $_, "\n";
}
省略して @$b と書いても良いです。

この状態で@aの内容を変更すると以下のようになります。

Perlのコード
$a[0] = 100;

イメージ($a[0]が100になった)
   ┌──┬──┐
@a │100 │  2 │
   └──┴──┘
     ↑
$b ─┘

実際に
print $b->[0], "\n";
と実行すると 100 と表示されます。
(3)配列のリファレンスの応用

応用1 多次元配列

配列の中に配列を入れることはできませんが、リファレンスはスカラーなので配列の
中に入れることができます。これによって多次元配列を扱うことができます。

my @a1 = (1, 2, 3, 4, 5, 6, 7, 8, 9);
my @a2 = (2, 4, 6, 8, 10, 12, 14, 16, 18);

my @z = (\@a1, \@a2);

print ${$z[1]}[1], "\n";

最後のところを->を使って書くと
print $z[1]->[1], "\n";
になります。多次元配列はリファレンスを使っていることが明らかなので、
省略して
print $z[1][1], "\n";
と書くこともできます。

イメージ
    ┌──┬──┬─
@a1 │  1 │  2 │・・・
    └──┴──┴─
        ↑
    ┌─┼┬──┐
@z  │  ││  ││
    └──┴─┼┘
        ┌──┘
        ↓
    ┌──┬──┬─
@a2 │  2 │  4 │・・・
    └──┴──┴─


応用2 関数に複数の配列を渡す

Perlの場合、関数で受け取った引数は一つのリストになるので複数の配列を渡しても
それを受け取る手段がありません。しかしリファレンスなら大丈夫です。

sub hoge {
    my $foo = shift;
    my $bar = shift;

    foreach my $i (0 .. @$foo-1) {
        printf "%2d + %2d = %2d\n",
            $foo->[$i], $bar->[$i], $foo->[$i] + $bar->[$i];
    }
}

my @a1 = (1, 2, 3, 4, 5, 6, 7, 8, 9);
my @a2 = (2, 4, 6, 8, 10, 12, 14, 16, 18);

hoge(\@a1, \@a2);
(4)無名配列

前々回に配列のリファレンスを作るために以下のように@aという配列を作って、
@aを参照する$bを作っていました。

@a = (1, 2);
$b = \@a;

しかしこれでは、配列のリファレンスが欲しいだけなのに配列を作らなくては
なりません。そんなときには以下のようにすると配列のリファレンスを作る
ことができます。

Perlのコード
$c = [1, 2];

イメージ($cは配列を参照している)
   ┌──┬──┐
   │  1 │  2 │
   └──┴──┘
     ↑
$c ─┘

このように[]を使うことで名前がない配列のリファレンスを得ることができます。

多次元配列についても同様で、

my @a1 = (1, 2, 3, 4, 5, 6, 7, 8, 9);
my @a2 = (2, 4, 6, 8, 10, 12, 14, 16, 18);

my @z = (\@a1, \@a2);

前回上記のように書いていたものを、

my @z = (
    [1, 2, 3, 4, 5, 6, 7, 8, 9],
    [2, 4, 6, 8, 10, 12, 14, 16, 18],
);

と書くことができます。

さらにここで
my $a = \@z;
とすれば多次元配列へのリファレンス得ることができ、
print $a->[1][1], "\n";
という形で値を参照することができます。

これも最初のところで、
my $y = [
    [1, 2, 3, 4, 5, 6, 7, 8, 9],
    [2, 4, 6, 8, 10, 12, 14, 16, 18],
];
このように書けば、同様に
print $y->[1][1], "\n";
という形で値を参照することができます。
(5)ハッシュのリファレンス

ハッシュのリファレンスについては考え方は配列のリファレンスと同じです。
書き方がちょっと違って [] の代わりに {} を使います。

%z = (foo => 1, bar => 2);
$a = \%z;
$b = {foo => 100, bar => 200};
print ${$a}{foo}, "\n"; # $a->{foo}ともかける
print $b->{foo}, "\n";  # ${$b}{foo}ともかける

という形になります。

関連項目

なし