0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Perlでハッシュに配列を入れたらハマった話

Posted at

はじめに

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を学び始めたばかりだったので、原因特定にだいぶ苦労しました。
そもそもなぜ配列リファレンスなんてあるのだろうと調べてみたところ、配列リファレンスを使用するとメモリの使用量を抑えられるようです。
そのため、基本的には配列リファレンスを使い、ループ処理など配列の要素を使用する際にデリファレンスする形が良いのではないかと思いました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?