リファレンス/デリファレンス
(3)
リファレンス
配列やハッシュといった変数をサブルーチンへの引数としてそのまま使うと、
sub foo {
my(@arg_a, @arg_b) = @_;
}
my @a = (1, 2, 3);
my @b = (4, 5, 6);
foo(@a, @b);
こういったコードを書いたときに、@arg_
には@a
の内容が、@arg_
には@b
の内容が入ることが期待されますが、@arg_
の中に@a
と@b
の内容が入ってしまいます。これは、
@_ = (@a, @b);
という擬似コードのような形で、@arg_
に@_
のすべての内容が渡されます。
そこでリファレンスの出番です。リファレンスは値を記録する代わりに、
リファレンスは、
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
になります。
ハッシュ
リファレンス
ハッシュのリファレンスも配列のリファレンスと同様に、
my %hash = (
'Blue' => '#0000FF',
'Red' => '#FF0000',
);
my $hash_ref = \%hash;
無名ハッシュの場合は{}
を使います。
$hash_ref = {
'name' => 'Dog',
'age' => 2,
};
デリファレンス
デリファレンスするにはリファレンスの変数名の先頭に%
を付けてハッシュ全体として参照するか、
my $hash_ref = {'name' => 'Hideo', 'age' => '40'};
print "My name is $hash_ref->{name}. \n";
print "I am $hash_ref->{age} years old. \n";
# My name is Hideo.
# I am 40 years old.
ハッシュのデリファレンスの際の書き方も3種類あり、
print ${$hash_ref}{name}; # Hideo
print $$hash_ref{name}; # Hideo
print $hash_ref->{name}; # Hideo
%演算子を使ったデリファレンス
ハッシュの場合の全体像は次のようになります。
my $hash_ref = {'name' => 'Hideo', 'age' => '40'};
while ( ($key, $value) = each(%$hash_ref) ) {
print "key: $key \n";
print "value: $value \n";
}
実行結果は次のようになります。
key: name
value: Hideo
key: age
value: 40
サブルーチン
サブルーチンのリファレンスは次のように作ることができます。一般的に
$foo = sub { print "hello!\n" };
$foo->(); # hello!
これは、
my $foo = 'pen';
my $code = sub {
print "This is a $foo"; # This is a pen
};
複雑なデータ構造の取り扱い
仕事で扱うデータ構造では、
ここでは、
配列の中に配列リファレンスを入れる
配列の中に配列のリファレンスを入れることができます。
my @AoA = (
[ "cat", "dog", "koala" ],
[ "camel", "llama", "owl" ],
);
my $array_ref = \@AoA;
配列の中の配列のリファレンスにアクセスするための2つめ以降のアロー演算子は省略できます。
print $array_ref->[1]->[0]; # camel
print $array_ref->[1][0]; # camel
配列の中にハッシュのリファレンスを入れる
配列の中にハッシュのリファレンスを入れることができます。
my @AoH = (
{
name => "cat",
age => 10,
},
{
name => "dog",
age => 5,
},
);
my $array_ref = \@AoH;
先と同様に、
print $array_ref->[0]->{name}; # cat
print $array_ref->[0]{name}; # cat
配列のハッシュにアクセス
ハッシュのvalue要素に、
my %HoA = (
animals1 => [ "cat", "dog", "koala" ],
animals2 => [ "camel", "llama", "owl" ],
);
my $hash_ref = \%HoA;
print $hash_ref->{animals1}->[2]; # koala
print $hash_ref->{animals2}[1]; # llama
ハッシュのハッシュにアクセス
ハッシュのvalue要素に、
my %HoH = (
cat => {
count => 10,
},
dog => {
count => 5,
},
);
my $hash_ref = \%HoH;
print $hash_ref->{cat}->{count}; # 10
print $hash_ref->{dog}{count}; # 5
リファレンスの型を調べる
リファレンスの型が何であるかを調べるには、
my $man = {'name' => 'Hideo', 'age' => '40'};
if ( ref($man) eq 'HASH' ){
print "man is HASH";
}
Perl 5.14からデリファレンスが変わる!!
今後リリース予定のPerl 5.
今までは、
my $array_ref = [1, 2, 3, 4];
push @{ $array_ref }, 5;
と書かなければなりませんでしたが、
my $ref = [1, 2, 3, 4];
push $ref, 5;
と書けるようになり、{}
を付けるかどうか悩んでいた人には朗報でもあります。
また、%{}
や@{}
を付けて明示的に何の型のリファレンスであるかを表現しなくてもよくなります。
for ( keys %{$hoh->{hok}} ) {...} # Perl 5.12以前
for ( keys $hoh->{hok} ) {...} # Perl 5.14以降
本稿執筆中には、
リファレンスは怖くない
本節では、
Perlにはperldocと呼ばれるたくさんの公式ドキュメントがあり、
- Perlのリファレンスに関する概要ドキュメント
- http://
perldoc. jp/ docs/ perl/ 5. 10. 0/ perlref. pod - Perlのリファレンスに関するチュートリアル
- http://
perldoc. jp/ docs/ perl/ 5. 10. 0/ perlreftut. pod
おわりに
今回は
次回の執筆者は広木大地さんで、