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/ライブラリ・モジュールとオブジェクト指向の項で扱います。