• ベストアンサー

Perl連想配列の使い方について

はじめまして。 現在、業務で他人の書いたコード(Perl)を改造しているのですが、その作成者がいなくなってしまっております。 そのコードを見ると、なぜ、このような書き方が可能なのか、理解できないので、動作原理を教えていただけないでしょうか? 以下のようなコードです。 ==================================== my @arr = ( "一" , "ニ" , "三" , "四" ) ; my %data ; $data->{0} = \@arr ; $data{0}{test} = "テスト" ; print ${$data->{0}}[1] . "\n" ; print $data{0}{test} . "\n" ; ==================================== 出力はこのようになります。 ニ テスト ここからが質問なのですが、$data->{0}という書き方ができる理由が分からないのです。 $dataが例えば、 my %my_hash ; my $data = \%my_hash ; というように、ハッシュのリファレンスであるならば、$data->{0}という書き方も分かるのですが、定義した時点でリファレンスではない、$dataに、何故"->"の演算子が使えるのでしょうか? とはいえ、 ref $data ; の戻り値がHASHとなるのも確認しています。 これもどうしてそうなるのか、根本的な原理が分かっておりません。 どうか、このコードの動作原理を教えていただけないでしょうか。 抽象的な質問となっている気がしますが、宜しくお願いいたします。

  • Perl
  • 回答数2
  • ありがとう数2

質問者が選んだベストアンサー

  • ベストアンサー
noname#25358
noname#25358
回答No.1

 自動的に作成されるからです。  Perl の場合、「未定義の変数にはすべて undef が代入ずみ」という仮定になっています。  よって、宣言していない $data という変数にも、いきなりアクセスできてしまうのです。  $data->{0} という記述をすると、Perl は自動的にハッシュのリファレンスを構築します。  理論上は、10次元配列とかでも宣言なしでアクセス可能です。

lawfer
質問者

お礼

ご回答ありがとうございます。 自動的に作成されるということで、 my %data ; の宣言文をコメントアウトしても、全く同様に動くことが確認できました。 つまり、%dataという実ハッシュ宣言自体は、今回のケースにおいては意味を持たないということですね。 大変分かりやすい回答ありがとうございました。

lawfer
質問者

補足

大変申し訳ありません。 もう1つ分かっていない点があることが分かりましたので、補足させてください。 まず、 my %data ; これについては、特別意味がないわけですよね。 その後、突然、 $data->{0} という記述が出るため、Perlが、$dataは、 「ハッシュのリファレンスである」 と判断し、作成をするわけですね。 となると、その後で、$data{0} という書き方が可能なのは何故なのでしょうか? ハッシュのリファレンスにキーをつけて参照や書き込みをするならば、 $data{0} ではなく、 ${$data}{0} となるような気がするのですが・・・。 もしよろしければ教えてください。

その他の回答 (1)

  • 3rd
  • ベストアンサー率30% (7/23)
回答No.2

どうやら基本的な部分で誤解されているようなので、補足します。 perl では、$data と %data は全く別の変数を表します。 (ついでに @data も上記の2つとは別変数) ですから、ご質問のプログラム内の $data->{0} と $data{0}{test} は別の変数になります。 $data{0}{test} は、2行目で定義されている連想配列を 参照しており、 $data->{0} は、宣言なしでいきなり使用された変数($data)を参照していることになります。 では、2行目に全く意味がないのかというとそうでもなく、 my で宣言していることから変数のスコープ(ローカル変数とかグローバル変数とか)を定義していると考えられます。

lawfer
質問者

お礼

回答ありがとうございます。 本当に根本的な部分で誤解をしていました。 $data, %dataが同時利用可能であることは知りませんでした。 (他の言語でもありうるのでしょうか?) だとすると、my宣言の意味も分かります。 (質問文に記載したコードでは意味が薄いかもしれませんが・・・) これで全て分かりました。 皆様本当にありがとうございました。

関連するQ&A

  • ハッシュの中身の表示

    ハッシュの中身の確認ができなくて困っています。 下記のような実行文においてです。 当然、test の戻り値は、スカラーとハッシュです。ハッシュを戻すときには参照渡し記号の\もつけています。 my ($return_code, %hash_data) = test(); 表示しようとすると、 Hash(0x5b04) のような表示にしかなりません、、 (試した表示方法は、下記4つです。) (環境は、WindowsXP上での、ActivePerl-5.10.0.1004 です。) foreach $key ( keys( %Hash ) ) { print "キー値 : $key\n"; print "値 : $Hash{$key} \n " } while ( ( $key , $value ) = each %Hash ){ print "キー値 : $key\n"; print "値 : $value \n " ; } use Data::Dump qw(dump); print dump(\%hash); #print %display_test; 宜しくお願いします。

    • ベストアンサー
    • Perl
  • ハッシュリファレンスの無名変数

    サブルーチンにハッシュリファレンスを渡すために、 以下のようにすると上手く実行されます。 %hash = ( baa => 1, boo => 2 ); test(\%hash); sub test { my %hash = %{shift}; print $hash{baa}; } これを、%hashに格納せずに、 直接渡そうとすると上手くいきません。 test(\( baa => 1, boo => 2 )); 考え方が間違っているのでしょうか。

    • ベストアンサー
    • Perl
  • Perlのデータ構造について

    Perlのデータ構造でわからないところがあります。 ハッシュの配列で、以下の構造がある場合 my %hash_array = ( 1=>["aaa", "bbb"], 2=>["ccc", "ddd", "eee"], 3=>[], 4=>["fff"] ); print $hash_array{1}[0]; # aaaが表示される。 print $hash_array{2}[2]; # eeeが表示される。 ですが、 $hash_array{1}は 2 $hash_array{2}は 3 $hash_array{3}は 0 $hash_array{4}は 1 のように個数を表示させるのは、どうすればよいでしょうか? Perlのデータ構造に詳しいサイトや書籍はありますか? また、Perl 5.6.1から Perl 5.8.7に乗りかえようとしていますが、 データ構造など大幅に変わった点はあるのでしょうか?

    • ベストアンサー
    • Perl
  • Perlは戻り値で、ハッシュや配列を正しく返さないのでしょうか?

    Perlは戻り値で、ハッシュや配列を正しく返さないのでしょうか? 返せるように見えて実際は、歯抜けのデータなど、不安定で使い物になりません。 よって、リファレンスでスカラー値で利用するのが正論でしょうか? $a = ''; %b = (); @c = (); ○ return ($a, \$b, \$c); × retuen ($a, %b, @c); ○ my ($a, $b, $c) = aru_kansuu($hikkey, ('komori')); × my ($a, %b, @c) = aru_kansuu($hikkey, ('komori'));

    • ベストアンサー
    • Perl
  • 参照配列の要素数の求め方は?

    リファレンス配列の要素数は、$#では求められないのでしょうか? ------------------------------------- foreach $i(0 .. 3){ $hash->[$i] = $i * 100; } print "\%hashの要素数->$#hash\n"; $ref = \%hash; print "\%{$ref}の要素数->$#{$ref}\n"; -------------------------------------

    • ベストアンサー
    • Perl
  • ハッシュのリファレンスを用いた処理

    ActivePerl 5.8 , WinXP SP2の環境です。 Perl スクリプトを用い、ファイルから複数のブロックからなる情報をよみとり、個別のハッシュを作り、それをリファレンスの配列としてまとめて後から参照するという操作をしたいのですが、詰まってしまいました。。 例として読み取るファイルは ---input.txt--------- >1 Jan 1 Feb 4 >2 Mar 9 Apr 3 >3 Oct 8 Nov 4 ------------------ ここから1,2,3の個別のハッシュ {Jan => 1 Feb => 4} {Mar=> 9 Apr =>3} {Oct =>8 Nov =>4} を作成し、それぞれのハッシュのリファレンスの配列をつくり、その後からすべてのハッシュの中身を個別に出力させたいと思いました。 次のようなスクリプトを作成したのですが思ったように作動しません。 use strict; open (IN, "input.txt") or die ("cant open file \n"); my $reff; my @array_of_reff; my %hash; my $count = 0; while(<IN>){ my $line = $_; ######ここでは各ブロックの頭の ">"を認識し、2個目以降であれば直前までで作ったハッシュのリファレンス($reff)を配列@array_of_reffに入れる。 if($line =~ /^>/){ if($count >0){ $reff = \%hash ; push (@array_of_reff, $reff); %hash = (); } $count++; } ########ここではアルファベットが入った行を認識して、ハッシュに追加しています if($line =~ /^[A-Za-z]/){           $line =~ /([A-Za-z]+)\s+/; my $month = $1; $line =~ /\s+(\d+)/; my $day= $1; $hash{$month} = $day;     } ###ここはファイルの最後になったら直前まで作っていたハッシュののリファレンス($reff)を配列@array_of_reffに入れる。 if( eof ){ $reff = \%hash ; push (@array_of_reff, $reff); } } #####ハッシュのリファレンスの配列(@array_of_reff)からもとのハッシュを参照し、ハッシュごとに出力 foreach my $reff_of_hash (@array_of_reff){    print "output";    while( (my $key,my $value) = each %$reff_of_hash ){     print "\n" , $key, " : ", $value, ;    } } このスクリプトを実行すると Nov 4 Oct 8 という3つめのハッシュのなかみが3回出力されてしまいます。自分では3つの別のハッシュをつくっているつもりでも、どうやら1種類しか作れていない、もしくはハッシュが上書きされているようなのですが、原因がわかりません。 この例だけ見るとハッシュのリファレンスを使う必要はないのですが、実際にはもうすこし大きいスクリプトで"ハッシュのリファレンスの配列を他のサブルーチンに渡す"ということを想定しており、これが解決できず先に進めない状態です。 アドバイス、解決法がわかったら教えていただけないでしょうか。

    • ベストアンサー
    • Perl
  • perl:2次元配列の値の取り出し方

    お世話になります。Perlの2次元ハッシュ配列の値の取り出し方をお教えください。以下の コード中、%test だと、値を入れるのが煩雑になるので、%test2や%test3のようなコードにしようと思うのですが、入れた値をとりだすコードが分かりません。。。ご指導ください。 my %test; $test{'A'}{'a'} = 1; $test{'A'}{'b'} = 2; my %test2 = ( 'P' => ['a'=>1, 'b'=>2], 'Q' => ['a'=>3, 'b'=>4] ); my %test3 = ( 'P' => ('a'=>1, 'b'=>2), 'Q' => ('a'=>3, 'b'=>4) );

    • ベストアンサー
    • Perl
  • perl 配列名変数指定するには

    perlプログラムで for文で ループ分の配列定義するには どうしたらよいですか? 下記のようなことができないかと 考えております。 for(my $i = 0; $i < $file_no; $i++){ my @{"segments$i"} =(); #配列定義 my ${"line$i"}="";     #変数定義 my %{"hash$i"}= ();    #ハッシュ定義 open(ARG1,$ARGV[$i]); while(<ARG1>){ ${'line'.$i} = $_; chomp ${'line'.$i}; @{'segments'.$i} = split(/\t/,${'line'.$i});        ${'hash'.$i}{${'segments'.$i}[0]}=${'segments'.$i}[1];     } close(ARG1); } #下記で、その後 各ハッシュに設定したデータをもとに いろいろ計算したい foreach my $a (keys %{'hash'.$i}){ ・・・ } 今は、Can't declare array dereference in "my" at test.pl line XX, near "} =" と 配列定義でエラーとなり処理できません。

    • ベストアンサー
    • Perl
  • ハッシュのリファレンスを戻り値にしたい

    PHPでハッシュのリファレンスを戻り値にする方法が知りたいです。 perlでは return \%hash; ですが、phpではどうなるのでしょうか? 他に別の方法があるのでしたらそれでも構いません。

    • ベストアンサー
    • PHP
  • foreach内での$_の書き換え

    数年前にハッシュのデータをforeachで取り出す時、$_をいじると、$_はハッシュのデータと直接つながっているので、ハッシュのデータ(keyは変わらずvalueのほう)が書き換わってしまうと聞き、実際にやってみて書き換わってしまった覚えがあります。 %hash = ("red" => "aka", "green" => "midori", "blue" => "ao", "black" => "kuro"); foreach (%hash){ print "$_<br>\n"; $_ = "modify"; } print "<hr>\n"; foreach (values %hash ){ print "$_<br>\n"; } ↓↓↓↓↓↓html↓↓↓↓↓↓↓ blue ao green midori red aka black kuro ------------------------------------ modify modify modify modify ↑となったはず 先日それを試してみたら書き換わりませんでした。 以前は確かに書き換わった覚えがあります。 perlの仕様が変わったのでしょうか。それとも私が何か間違っているのでしょうか。 詳しい方にお教えいただければと質問しました。 よろしくお願いいたします。

    • ベストアンサー
    • Perl

専門家に質問してみよう