メインメニューを開く

Perl/リファレンス

< Perl
プログラミング > Perl > リファレンス

目次

多次元配列編集

配列の中に配列が入っているものを多次元配列といいます。Perlで多次元配列を生成するには、単に配列の中に配列を入れようとしても、

my @x = ("A", "B", "C");
my @y = ("D", "E", "F");
my @a = (@x, @y); # @a = ("A", "B", "C", "D", "E", "F")

うまくいきません。これでは@xと@yが展開され、単なる配列(一次元配列)になってしまいます。正しくは次のようにします。

my @x = ("A", "B", "C");
my @y = ("D", "E", "F");
my @a = (\@x, \@y);

print $a[0][0]; # A
print $a[0][1]; # B
print $a[0][2]; # C

print $a[1][0]; # D
print $a[1][1]; # E
print $a[1][2]; # F

\@xのように、配列のシジル「@」の前に「\」を付けます。$a[0][0]とは、@aの0番目の要素 (\@x) の0番目の要素 ("A") を表します。このようにして多次元配列を生成し、多次元配列の要素にアクセスすることができます。

最初に示した例では、@xや@yが("A", "B", "C")のように展開されてしまったため、うまくいきませんでした。

my @x = ("A", "B", "C");
print @x; # ("A", "B", "C");

多次元配列のようなものを作るためには、「\@x」として、「@x」という配列自体を指し示す必要があります。これは""でクォートされた文字列の中で、「"」という文字そのものを表すのに「\"」とするのと似ています。

リファレンス編集

リファレンスとは、あるデータが格納されている場所を指し示すデータ型です。データに「\」を前置して生成します。

my $a = 42;
my $b = \$a;

このとき、$bには$aのリファレンスが代入されます。

my $a = 42;
my $b = \$a;
print $b;

$bを出力すると、

SCALAR(0x9d3e198)

このように表示されます。SCALARというのは、$aのデータ型がスカラであることを表しています。(0x9d3e198)は、$aが格納されている場所(メモリアドレス)を表しています。なお、0x9d3e198という数値は環境によって異なります。

$bから$aの値を取り出すには、$bに$aのデータ型であるスカラのシジル「$」を前置します。

my $a = 42;
my $b = \$a;
print $$b; # 42

さて、$bには$aのメモリアドレスが入っているということは、$aの値が変わっても、$bは常に$aの値を参照することができるのです。次の例をご覧ください。

my $a = 42;
my $b = \$a;
$a = 10000;
print $$b; # 10000

これがリファレンスというものです。

$bに代入されたのは42や10000という数値そのものではなく、それらを保持している$aという変数の番地です。$$bは常に「そのとき$aに入っているもの」を表します。

スカラだけでなく、様々なデータ型のリファレンスを生成することができます。

\42; # スカラのリファレンス
\$x; # スカラのリファレンス
\@x; # 配列のリファレンス
\%x; # ハッシュのリファレンス
\&x; # サブルーチンのリファレンス
\*x; # 型グロブのリファレンス
\\$x; # スカラのリファレンスのリファレンス

「\」はリファレンスを生成するための単項演算子です。リファレンスそのものはスカラの一種です。

「$」や「@」のようなシジルを前置してリファレンスから元のデータを取り出すことを、デリファレンスするといいます。

リファレンスはC言語のポインタに似ていますが、より抽象的で安全だとされています。

リファレンスを使うのは、配列の配列などの複雑なデータ構造を扱う場合や、オブジェクトを扱う場合、サブルーチンに参照渡しを行う場合などに限られます。通常の配列やハッシュを使えば済む場面で、リファレンスを使うことはありません。

データを百科事典の記事の内容だとすれば、リファレンスはその記事が「何ページ目にあるか」に当たります。

スカラのリファレンス編集

my $x = \42;
print ${ $x }; # 42
print $$x; # 42

my $y = \$x; # \\42
print ${ ${ $y } }; # 42
print $$$y; # 42

配列のリファレンス編集

my @x = ("A", "B", "C");
my $a = \@x;
print @$a; # ABC

回りくどいことをしなくても、要素を()の代わりに[]で囲むと、直接配列のリファレンスを生成することができます。

[]の前に+を付けて+[]と書くこともあります。意味は同じです。

my $a = ["A", "B", "C"];
print @$a; # ABC

配列のリファレンスの要素にアクセスするには、->を使います。

my $a = ["A", "B", "C"];
print $a->[0]; # A

->を付けないと普通の配列として扱われてしまうため、->を付ける必要があります。ただし、

$a = ["A", ["B"], "C"];
print $a->[1]->[0]; # B
print $a->[1][0];

最初の->以外は省略することができます。なぜならば、省略しても他の文法とぶつかることがないからです。

->を使わない方法もあります。

my $a = ["A"];
print $a->[0]; # A
print ${ $a }[0]; # A
print $$a[0]; # A

配列の要素はスカラなので、$aに$を前置するのです。$$a[0]は${ $a[0] }ではなく、${ $a }[0]という意味です。

多次元配列でも同様です。

$a = [["A"]];
print $a->[0][0]; # A
print ${ $a }[0][0]; # A
print $$a[0][0]; # A

どちらを用いても構いませんが、${ $a[0] }[0]と$a[0][0]では後者のほうが見やすいとされることもあります。また変数展開コンテキストの中では、$a->[0][0]ではなく$$a[0][0]と書かなければなりません。

ハッシュのリファレンス編集

ハッシュのリファレンスを生成するには、次のようにします。

my %a = ( a => "Apple" );
$a = \%a;
print %$a; # aApple

要素を{}で囲むことで、直接ハッシュのリファレンスを生成することができます。

{}の前に+を付けて+{}と書くこともできます。意味は同じですが、コードブロックと違うことを明示できるため、そのように書く人もいます。

my $a = { a => Apple };
print %$a; # aApple

%$aは通常のハッシュと同じように扱うことができます。ハッシュの値にアクセスするには、次のようにします。

my $a = { a => "Apple" };
print $a->{a}; # Apple
print ${ $a }{a}; # Apple
print $$a{a}; # Apple

$a->{a}->{a}は$a->{a}{a}と書くことができます。

サブルーチンのリファレンス編集

サブルーチンのリファレンスを生成するには、次のようにします。

sub print_hoge { print 'hoge' }
my $ref = \&print_hoge;

サブルーチンを実行する時とは違い、サブルーチン名の前に&を付けてサブルーチンであることを明示させる必要があります。

サブルーチンのリファレンスからサブルーチンを実行するときは、次のようにします。

$ref->(); # hoge と出力される

引数を渡すときは普通に()の中に引数を書けば渡せます。

また、次のように書くことで、サブルーチンのリファレンスを直接書くこともできます(クロージャや、無名サブルーチンとも呼ばれます)

my $ref = sub { 処理... };

サブルーチンのリファレンスには特別な性質があり、サブルーチンのリファレンスを生成した時の環境を保存します。

例えば、以下のようなコードがあったとします:

sub print_hello_name {
  my ($name) = @_; # 引数受け取り
  return sub { # サブルーチンリファレンスを返却
    print "Hello $name!!";
  };
}
my $ref = print_hello_name('Kenta'); # 実行すると Hello Kenta!! と表示されるサブルーチンリファレンスが変数$refに格納される
my $ref2 = print_hello_name('Taro');
$ref->(); # サブルーチンリファレンスを実行、Hello Kenta!! と表示される
$ref2->(); # Hello Taro!! と表示される

正規表現のリファレンス編集

他のリファレンス生成と少しやり方が異なりますが、正規表現のリファレンスを生成することも可能です。 正規表現のリファレンスを作るには、正規表現の前にqrを付けます。

my $regex = qr/.pm$/; # 文字の最後に「.pm」が付いている文字にマッチする正規表現のリファレンスを生成

正規表現のリファレンスを使うには、次のようにします:

# 引数の最後に「.pm」が付いているかどうかを調べるサブルーチン
sub match_pm {
  my ($name) = @_;
  my $regex = qr/.pm$/;
  if ($name =~ /$regex/) {
    print "マッチしました\n";
  } else {
    print "マッチしていません\n";
  }
}
match_pm('test.pm'); # マッチしました と表示される
match_pm('test.pl'); # マッチしていません と表示される

置換する時も、s/$regex/置換後の文字/g という感じで使用できます。

オブジェクト指向におけるリファレンス編集

Perl/ライブラリ・モジュールとオブジェクト指向の項で扱います。

このページ「Perl/リファレンス」は、書きかけです。加筆・訂正など、協力いただける皆様の編集を心からお待ちしております。また、ご意見などがありましたら、お気軽にノートへどうぞ。