リファレンス変数

Perl にはリファレンス型の変数が用意されている。一般的な変数は値を保存するが、リファレンス型の変数は値のアドレスを保存する。これを利用することで、二次元配列、二次元ハッシュ、または配列のハッシュなどの複雑なデータ構造を実現することができる。

リファレンス変数の宣言

リファレンス型の変数は、変数名の前に $ を付ける。これは普通の変数と区別しにくい。リファレンス変数は、アドレスを保存する変数である。すなわち、リファレンス変数を利用するときは、代入対象のアドレスを予め調べておく必要がある。アドレスを調べるには \ を利用する。

配列のリファレンス

リファレンス変数に配列を代入する場合は 2 通りの方法がある。1 つは、配列 @arr を先に作り、そのアドレスを $ref_arr に代入する。もう 1 つの方法は、@arr を作らずに、最初からリファレンス変数に配列を代入することである。

## 方法 1
my @arr = ('A', 'C', 'G', 'T');   # 配列を作成
my $ref_arr = [];                 # 配列用リファレンス型の変数を作成
$ref_arr = \@arr;                 # 配列のアドレスをリファレンス変数に代入


## 方法 2 
my $ref_arr = ['A', 'C', 'G', 'T'];

ハッシュのリファレンス

ハッシュをリファレンス変数に代入する場合も、配列と同様に 2 通りの方法がある。

## 方法 1
my %hash = ('AUG' => 'M', 'GUA' => 'V');   # ハッシュを作成
my $ref_hash = {};                         # ハッシュ用リファレンス型の変数を作成
$ref_hash = \%hash;                        # ハッシュのアドレスをリファレンス変数に代入


## 方法 2 
my $ref_hash = {'AUG' => 'M', 'GUA' => 'V'};

リファレンス変数から値を取得

リファレンス変数にはアドレスが保存されている。変数名に $ を付けると、そのアドレスを参照することになる。そのため、値を参照するために、更にもう一つの $ を利用して、アドレス先の値を呼び出す必要がある。

スカラー変数

例えば、普通の変数のリファレンスを例にすると、以下のように $$ で値を取得できる。


my $pi = 3.14;            # 普通の変数
my $ref = \$pi;           # 普通の変数のアドレスをリファレンスに代入

print $ref;
print ${$ref};            # $$と同じ意味。ここではわかりやすいように括弧を付けている


## 出力結果
## SCALAR(0x1148d88)
## 3.14

$$ は次のように理解するとわかりやすい。$pi = 3.14 がまず与えられている。続いて $ref = \$pi が与えられている。または $\ は逆関数のようなものと考えれば、$$ref = $($ref) = $(pi) = $pi = 3.14 となる。

配列

配列の場合はアロー演算子 -> を用いて、各要素を取得する。

my @arr = (1, 1, 2, 3, 5, 8, 13);
my $ref = \@arr;

# $arr[0] を取得
print $ref->[0]; 

# $arr[3] を取得
print $ref->[3];

配列の要素をすべて取得する場合は、以下のように for 文を用いる。

my $ref = [1, 1, 2, 3, 5, 8, 13];

for (my $i = 0; $i < @{$ref}; $i++) {
  print $ref->[$i];
}

$ref には配列のアドレスが保存されている。@{$ref} とすることで、$ref の指すアドレスを辿って配列を見つけ、それを配列に復元することができる。

ハッシュ

ハッシュの場合はアロー演算子 -> を用いて、各要素を取得する。

my %hash = ('AUG' => 'M', 'GUA' => 'V');
my $ref = \%hash;

# $hash{'AUG'} を取得
print $ref->{'AUG'};

# $hash{'GUA'] を取得
print $ref->{'GUA'}

すべてのキーと値を取り出す場合は、配列と同様に %{$ref} を利用して、リファレンスをハッシュに復元させてから、for 文あるいは while 文を利用する。

my $ref = {'AUG' => 'M', 'GUA' => 'V'};


# for 文
for my $key (keys %{$ref}) {
  print $ref->{$key};
}

# while 文
while (my ($key, $val) = each %{$ref}) {
  print "$key   ===>   $val";
}