はじめに
sub return_hash{
my @fruits = ('apple', 'banana', 'orange');
return{
result => 1,
data => @fruits
}
}
my $result = return_hash();
print $result->{result};
print $result->{data};
突然ですが、上記のコードを実行したら何が出力すると思いますか?
自分の予想では「1applebananaorange」となると思っていました。
しかし、実際には以下が出力されました。
1apple
「ん?」となり、これにだいぶハマりました。。。
原因を調べてみると、ハッシュの動作や配列・配列リファレンスの違いを理解していなかったことが問題でした。
ハッシュについて
ハッシュは「キー」と「値」のペアでデータを管理するデータ構造です。
PHPでは「連想配列」、Javaでは「Map」と呼ばれています。
my %user = (
name => 'Taro',
age => 25,
city => 'Tokyo'
);
print $user{name}; # 出力: Taro
print $user{age}; # 出力: 25
ハッシュの特徴として、スカラー値しか保持できません。
配列と配列リファレンスについて
配列
配列は他の言語と同じような形です。
my @fruits = ('apple', 'banana', 'orange');
print @fruits;
# 出力:applebananaorange
配列リファレンス
Perlでは、配列の前に「\」をつけると、配列のメモリアドレスを取得でき、これを配列リファレンスと呼びます。
my @fruits = ('apple', 'banana', 'orange');
print \@fruits;
# 出力: ARRAY(0x55b81ea564c8)
ARRAY(0x...) というのは、配列がメモリ上のどこにあるかを示すアドレスです。
何が問題だったのか?
最初のコードでは、配列 @fruits をそのままハッシュに入れていました。
return {
result => 1,
data => @fruits # 配列がここで展開されてしまう
}
前述のとおり、Perlのハッシュはスカラー値しか持てません。
配列を代入させようとすると、配列の要素がバラバラに展開されてしまいます。
実際には以下のように解釈されます。
return {
result => 1,
data => 'apple', # data の値は 'apple' だけ
banana => 'orange' # banana が新しいキーになってしまう
}
print $result->{result};
print $result->{data};
そのため、このように出力されてしまいました。
1apple
ハッシュにはスカラー値しか入れられないため、配列の情報を渡すには配列リファレンス(スカラー値)を使う必要があります。
sub return_hash{
my @fruits = ('apple', 'banana', 'orange');
return{
result => 1,
data => \@fruits
}
}
ちなみに、受け取り側ではデリファレンスが必要
配列リファレンス形式で返却されたため、受け取り側でそのまま使うとアドレス値が出力されてしまいます。
my $result = return_hash();
my $array_ref = $result->{data};
print $array_ref;
# 出力: ARRAY(0x55b81ea564c8)
そのため、配列リファレンスから配列へ変換する必要があり、この変換をデリファレンスと呼びます。
デリファレンスは配列リファレンスを「@{}」で囲みます。
my $result = return_hash();
my @array_dereference = @{$result->{data}}; # デリファレンス
print @array_dereference; # applebananaorange
さいごに
Perlを学び始めたばかりだったので、原因特定にだいぶ苦労しました。
そもそもなぜ配列リファレンスなんてあるのだろうと調べてみたところ、配列リファレンスを使用するとメモリの使用量を抑えられるようです。
そのため、基本的には配列リファレンスを使い、ループ処理など配列の要素を使用する際にデリファレンスする形が良いのではないかと思いました。