Perl - リファレンスの説明(1)

Perl 初心者が初心者なりにリファレンスを説明してみる。「初めてのPerl」を読み終わって、いざ何かやろうと思ってもリファレンスが分かってなかったら何もできなかった。
リファレンスとは、厳密には知らないけど、変数の置いてある場所のアドレスのことと理解しよう。C 言語のポインタと同じだと思ってもいんじゃないだろうか。ただしリファレンスに1を足して次の要素が得られるといったことはありません。
はじめてリファレンスを学んだとき $$ref[0] とかが出てきて区切りが分からなくて理解しにくかった。よってこの説明では冗長だけど ${ $ref }[0] のように書く。

以下の説明では括弧の種類、つまり丸括弧()、ブラケット[]、ブレース{} の違いを意識しながら読んでほしい。

目次

  1. 復習 $, @, %, &
  2. 復習 ループ
  3. リファレンス
  4. リファレンスを使って多次元配列

参考文献

  1. 深沢千尋, すぐわかる オブジェクト指向 Perl, 技術評論社
  2. Randal L. Schwartzほか, 続・初めてのPerl, オライリー

「すぐわかる オブジェクト指向 Perl」はとても分かり易いと思う。

1.復習 $, @, %, &

Perlスカラー変数、配列、ハッシュ、サブルーチンの書き方は

my $scalar = "text";
my @array  = ("A", "B", "C");
my %hash   = ("jp", "Japan", "kr", "South Korea", "cn", "China");
sub function { print "Hello!\n" }

だった。配列、ハッシュを作るのには丸括弧 () を使うことを覚えておく。ハッシュ %hash はキーとそれに対応する値からなるもので、普通はもっと見やすいように次のようにして作る。

# => はカンマ, と同じ意味
my %hash = ( 
    "jp" => "Japan",
    "kr" => "South Korea",
    "cn" => "China"
);
# さらに、キーは空白なしのとき、クオートせずに裸でもいいので下のようにも書ける
my %hash = ( 
    jp => "Japan",
    kr => "South Korea"
    cn => "China"
);

配列、ハッシュの要素にアクセスするには

$array[2]   # C 
$hash{'jp'} # Japan
# キーは空白なしの場合、裸でもよい
$hash{jp}   # Japan

とした。ここで

  • 配列、ハッシュの要素はスカラーなので先頭が $
  • 配列の番号は 0 から始まる
  • 配列の番号指定はブラケット[ ]
  • ハッシュのキー指定はブレース{ }

に注意。

2.復習 ループ

配列 @array のすべての要素に対して繰り返し何かするときは for を使う。

# 方法1
for (@array) {
    # 各要素は $_ に入る
    print $_, "\n";
}
# 方法2
for my $item (@array) {
    # 各要素は $item に入る
    print $item, "\n";
}

ハッシュ %hash の方は、

# 方法1
while (my ($key, $value) = each %hash) {
    # 各キーと値のペアは $key, $value に入る
    print "$key=$value\n";
}
# 方法2 ハッシュのキーのリストを返す keys を使って
for (keys %hash) {
    print "$_=$hash{$_}\n";
}

のようにする。

3.リファレンス

リファレンスとは、変数の置いてある場所のアドレスということにしておこう。で、それを取得するには変数の前にバックスラッシュ(Windowsは円マーク)\ を置けばいい。つまり

my $scalar_ref   = \$scalar;
my $array_ref    = \@array;
my $hash_ref     = \%hash;
my $function_ref = \&function;

とすることによって $scalar_ref, $array_ref, ... にリファレンスが入る。ここでリファレンスはアドレスなのでスカラー変数に格納する。
こうして得られたリファレンスから、元の変数を得るにはスカラー、配列、ハッシュ、サブルーチンに合わせて ${ }, @{ }, %{ }, &{ } としてあげればいい。つまり

${ $scalar_ref   } # $scalar のこと
@{ $array_ref    } # @array のこと
%{ $hash_ref     } # %hash のこと
&{ $function_ref } # &function のこと

とすればいい。これを使って、例えばハッシュの while ループは

while (my ($k, $v) = each %{$hash_ref}) {
    print "$k=$v\n";
}

と書ける。
配列、ハッシュのリファレンス $array_ref, $hash_ref から要素にアクセスするには @{ }, %{ } ではなく${ }[], ${ }{} を使って、

${ $array_ref }[2]  # C
${ $hash_ref  }{jp} # Japan

とする。

4.リファレンスを使って多次元配列

リファレンスって何に使うのよ、ということでその例を紹介。Perl で多次元配列(行列、ネストした配列)を作ろうと思って

my @matrix = (
    (10,20,30),
    (40,50,60),
    (70,80,90),
);

としても、Perl

@matrix = (10,20,30,40,50,60,70,80,90);

だと解釈してしまってうまくいかない。こんなとき、リファレンスを使う。つまり

my @first  = (10,20,30);
my @second = (40,50,60);
my @third  = (70,80,90);

と各行をまず作っておいて、そのリファレンスを @matrix に入れる:

my @matrix = (
    \@first,
    \@second,
    \@third
);

これで @matrix は2次元配列みたいになった。
この @matrix にアクセスしてみる。例えば2行目全体にアクセスしてみよう。$matrix[1] が \@second で、それをデリファレンスする(もとの配列を得る)には @{ } とすればよかったから

@{ $matrix[1] }    # (40,50,60)

でいい。さらにこれの第1要素 40 を得るには @{ } ではなく ${ }[0] をすれば良かったから、

${ $matrix[1] }[0]  # 40

となる。完璧。
最後に @matrix 全体の操作は for ループを使って

for my $line (@matrix) {
    # $line には @matrix の各要素、
    # つまり $matrix[0], $matrix[1], $matrix[2] が順に入る
    for my $item (@{ $line }) { # @{$line} でデリファレンス
        print $item, ',';
    }
    print "\n";
}
#
# 結果
# 10,20,30,
# 40,50,60,
# 70,80,90,

みたいにできる。
つづきは Perl - リファレンスの説明(2) - It'll be

今日の疑問

  • 「初めての Perl」にもリファレンスの説明を入れるべきでは?