2009/08/25(火)[perl] 多次元ハッシュ・配列~例示は何とやらの試金石

一次元

#!/usr/bin/perl -W

use strict ;

our %hash ;
our @hash ;

print \%hash . "\n" ;
print \@hash . "\n\n" ;


print " no-let: " . (exists($hash{hoge})?'true':'false') . "\n";


$hash{hoge} = ();
print " = (): " . ((exists($hash{hoge})?'true':'false')?'true':'false') . "\n";
print ref( $hash{hoge}) . "\n";
print \$hash{hoge} . "\n\n";

$hash{hoge} = [];
print " = []: " . ((exists($hash{hoge})?'true':'false')?'true':'false') . "\n";
print ref( $hash{hoge}) . "\n";
print \$hash{hoge} . "\n";
print $hash{hoge} . "\n\n";

$hash{hoge} = {};
print " = {}: " . (exists($hash{hoge})?'true':'false') . "\n";
print ref ($hash{hoge}) . "\n";
print \$hash{hoge} . "\n";
print ${\$hash{hoge}} . "\n\n";

$hash{hoge} = 1;
print " = 1: " . (exists($hash{hoge})?'true':'false') . "\n";
print ref( $hash{hoge}) . "\n";
print \$hash{hoge} . "\n\n";

出力例(環境や実行時により、値が異なる)


HASH(0x2e7214)
ARRAY(0x2e7204)

 no-let: false
 = (): true

SCALAR(0x1f81f4)

 = []: true
ARRAY
REF(0x1f81f4)
ARRAY(0x1f8294)

 = {}: true
HASH
REF(0x1f81f4)
HASH(0x1f82e4)

 = 1: true

SCALAR(0x1f81f4)

arrayの代入は、SCALARになるのか...


二次元(HASHにHASHを入れる)

#!/usr/bin/perl -W

use strict ;
use warnings ;
our %hash ;


print exists($hash{hoge});

# $hash{hoge} = {} ;
print $hash{hoge} . "\n" ; # ここで未初期化変数と文字列の結合でwarningが出る.
$hash{hoge}{foo} = 2 ;
$hash{hoge}{bar} = 44 ;
print $hash{hoge} . "\n" ;
print $hash{hoge}{foo} . "\n" ;    #これと
print $hash{hoge}->{foo} . "\n" ;  #これは 同意らしい.
print ${$hash{hoge}}{foo} . "\n" ;   # $hash{hoge}が hash referenceなので${}で デリファレンスして {}でハッシュ値をとってくる.という解釈で.
print (keys %{$hash{hoge}}) . "\n" ; # 装飾子みたいなもんかな..
#print (keys $hash{hoge}) . "\n" ;   # NG

出力例。

HASH(0x18881f4)
HASH(0x18881f4)
2
2
2
barfoo

perlreftut from Active Perl 5.10

説明資料があった…

Arrow Rule In between two subscripts, the arrow is optional.

Instead of $a[1]->[2], we can write $a[1][2]; it means the same thing. Instead of $a[0]->[1] = 23, we can write $a[0][1] = 23; it means the same thing.

Now it really looks like two-dimensional arrays!

You can see why the arrows are important. Without them, we would have had to write $$a[1][2] instead of $a[1][2]. For three-dimensional arrays, they let us write $x[2][3][5] instead of the unreadable $${$x[2][3]}[5].

無名配列、無名ハッシュを作る手段は2つしかなくて、(''と'')でハッシュのリファレンスを、('['と']')で無名配列のリファレンスを作る。


ハッシュと配列の混在例

以上を踏まえて、少し確認する。

#$hash{hoge} = () ; # case A
#$hash{hoge} = [] ; # case B
# case C

print $hash{hoge} . "\n" ;
$hash{hoge}[0] = {foo=>1};  # 要素0 へ 無名ハッシュのリファレンスを代入(fooをもつハッシュはどこかで作られる)
$hash{hoge}[1] = {bar=>3};  # 同様.
print $hash{hoge} . "\n" ;       # これは配列のリファレンス値を返すはず。

print $hash{hoge}[0] . "\n" ;    # この三つは同じ。ハッシュのリファレンス値を返す。
print ${$hash{hoge}}[0] . "\n" ; # 
print $hash{hoge}->[0] . "\n" ;  # 
  • case C\明示的に初期化しない場合。\perlさんが勝手に用意してくれました(Warningが出る)
  • case A\case Cと同様でした。初期化したことにもならない。
  • case B\配列リファレンスがセットされ、要素を追加してもリファレンス値が変わらず。

んー、なにやっても同じか。\warningを出さないように、明示的にカラの配列リファレンスを放り込んでおくのが無難かな。

では、なぜ、挙動が変わったのだろうか。ほかのところでいらんことしていたのかもしれないなぁ... 持ち帰れないのが悔やまれる('A`