Perl Hackers Hub

第7回 新人さんのための仕事で使えるPerl基礎知識(3)

この記事を読むのに必要な時間:およそ 4 分

リファレンス/デリファレンス

(3)では,仕事でPerlを使ううえで必ずと言っていいほど使用するにもかかわらず,つまずきがちなリファレンスとデリファレンスについて解説します。筆者も最初に教えてもらった際にはちゃんと理解できていませんでしたが,使っていくうちに徐々に体系的に理解できるようになりました。

リファレンス

配列やハッシュといった変数をサブルーチンへの引数としてそのまま使うと,少々困ったことになってしまいます。たとえば次のコードを書いたとします。

sub foo {
    my(@arg_a, @arg_b) = @_;
}
my @a = (1, 2, 3);
my @b = (4, 5, 6);
foo(@a, @b);

こういったコードを書いたときに,サブルーチンfooの引数に渡される値として,@arg_aには@aの内容が,@arg_bには@bの内容が入ることが期待されますが,実際には@arg_aの中に@a@bの内容が入ってしまいます。これは,

@_ = (@a, @b);

という擬似コードのような形で,2つの配列が1つの配列としてまとめられてしまうため,結果的に@arg_a@_のすべての内容が渡されます。

そこでリファレンスの出番です。リファレンスは値を記録する代わりに,値を格納しているアドレスをメモリ上に記録します。C言語の&演算子を使ってアドレスを得るものと同じような働きをします。

リファレンスは,変数名の前にバックスラッシュ演算子(/)を付けることで作成します。先ほどのコードをリファレンスを使って書くと次のようになります。

sub foo {
    my($arg_a_ref, $arg_b_ref) = @_;
}
my @a = (1, 2, 3);
my @b = (4, 5, 6);
my $a_ref = \@_;
my $b_ref = \@_;
foo($a_ref, $b_ref);

このように,リファレンスにすると配列のアドレスを表すスカラ変数として処理されるため,実質的に複数の配列を引数として渡しても,それぞれの配列の内容を別々に受け取ることができるようになります。

デリファレンス

このようにして作成したリファレンスが指している実体の値にアクセスすることを,デリファレンスと言います。

デリファレンスするときは,取得したい値の型に合わせて,$,@,%をリファレンスを格納している変数の頭に付けます。アロー->演算子を使い,わかりやすく表現できます。先ほどのコードをもとにすると次のように書くことができます。

sub foo {
    my($arg_a_ref, $arg_b_ref) = @_;
    print $arg_a_ref->[0]; # 1
    print $arg_b_ref->[0]; # 4
}

以降では,リファレンス/デリファレンスの使い方の詳細を見ていきます。

配列

リファレンス

配列のリファレンスを作成する場合,配列の変数にバックスラッシュ\を付けます。

my @array = qw/a b c d e/;
my $array_ref = \@array;

上記のようにわざわざバックスラッシュをつけてリファレンスを取得しなくても,直接的に無名配列のリファレンスを作ることができます。無名配列の場合はスカラに対して[]を使います。

$array_ref = [1, 2, ['a', 'b', 'c']];
デリファレンス

リファレンスにはあくまでもメモリ上の場所が格納されているため,実際に取り出す際にはデリファレンスすることで実体の値にアクセスします。デリファレンスするにはリファレンスの変数名の先頭に@を付けて配列全体として参照するか,アロー演算子を付けて配列の要素数を指定し配列リファレンスの一部を参照します。

my $array_ref = ["blue", "red", "black"];

print "My first color is:" . $array_ref->[0] . "\n";
# My first color is: blue

デリファレンスの際の書き方は3種類あり,次の例はどれも同じ結果になります。

print $array_ref->[0]; # blue
print ${$array_ref}[0]; # blue
print $$array_ref[0]; # blue
@演算子を使ったデリファレンス

リファレンスを作成し,デリファレンスして実体にアクセスするコードの全体は次のようになります。

my $array_ref = ["blue", "red", "black"];
foreach my $color ( @{$array_ref} ){
    print "color is $color \n";
}

実行結果は次のようになります。

color is blue
color is red
color is black
リファレンスの変数をそのまま表示する

配列のリファレンスをデリファレンスせずに表示するコードは次のようになります。

print "Reference: " . $array_ref . "\n";

実行結果は次のようになります。

Reference: ARRAY(0x1008d0040)

ARRAY(16進数)16進数部分はメモリ上の場所を意味しています。ARRAYはリファレンスの型が配列だということを表しています。もし後述するハッシュのリファレンスだった場合にはARRAYの部分がHASHになります。

著者プロフィール

横山彰子(よこやまあきこ)

大阪時代からWebシステム会社を数社経験後,2010年から本格的にフリーランスのエンジニアとして活動。現在もECサイト,新規サービスの立ち上げなどの開発支援を行う。

Perl Casual,Shibuya.pm,YAPC::Asia2010などスピーカーとして登壇。個人でも2008年からSmiley Hackathonやwebrick cafeなど勉強会の主催をしている。

Twitter:acotie

mail:acotie.acotie@gmail.com

URL:http://poccori.com

コメント

  • Re:

    リファレンスの説明の

    my $a_ref = \@_;
    my $b_ref = \@_;

    の箇所がわからないのですが、この代入式で、@aと@bのアドレスが、$a_ref、$b_refにそれぞれ格納されるのですか?
    @_は、どうやって区別をつけているのでしょうか?

    Commented : #1  めだか (2015/02/09, 10:33)

コメントの記入