• 締切済み

Perlのサブルーチンの引数に配列やハッシュをCall by Valueすることはできない?

leaz024の回答

  • leaz024
  • ベストアンサー率75% (398/526)
回答No.6

■パラメータ渡しの仕組みについて サブルーチンへのパラメータの渡され方ですが、まず、呼出側で指定したパラメータは1つのリストに展開されます。 そしてサブルーチン側では、そのリストの「別名配列」として @_ が用意されます。 @_ はパラメータリストの別名なので、$_[n] を操作することは、パラメータに指定した変数を直接操作していることと同じになります。 つまりPerlでは、常に「別名渡し」が行われます。 (即値やハッシュのキーのように別名が作れないものは、一時領域に値がコピーされ、その別名が渡るようです。) ちなみにパラメータが即値である場合、変更しようとするとエラーになります。 ■「値渡し」と「リファレンス渡し」について サブルーチン側でのパラメータの操作を、呼出側の変数に反映させたくない場合は、パラメータを「値渡し」にします。 Perlでの値渡しは、サブルーチン側で用意した my(または local)変数に @_ の値をコピーすることで実現します。 また、呼出側の変数の値を操作したい場合でも、$_[n] の内容を直接編集することはあまりなく、普通はリファレンスを渡し、それをデリファレンスして値を操作します。 # 「実体渡し」とは、何が渡ることを望んでいるのでしょうか? ■複数の配列やハッシュの渡し方 パラメータは、全てが1つのリストに展開されるため、複数の配列やハッシュを渡したい場合は注意が必要です。 例えば、次のように2つの配列を渡しても、   @x = qw(abc def);   @y = (1, 2, 3);   &f2(@x, @y);   sub f2 {     my (@a, @b) = @_;   # 2つの配列が欲しいのでこうしたが・・・     print "a:[@a]\n";     print "b:[@b]\n";   }  実行結果:   a:[abc def 1 2 3]   b:[] 1つ目の配列に、全て入ってしまいます。 これを回避するには、リファレンスを渡します。   &f3(\@x, \@y);   sub f3 {     my ($a, $b) = @_;   # リファレンスはスカラーなので、$変数で受け取る。     print "a:[@$a]\n";     print "b:[@$b]\n";   }  実行結果:   a:[abc def]   b:[1 2 3] ■サブルーチンからの戻値について サブルーチンからの戻値は、呼出時のコンテキストに依存します。 例えば、配列やハッシュ、リストを返していても、$変数で受け取っていたり、演算式に組み込んだりすると、それぞれに応じたスカラー値が返ります。 それ以外では、基本的にはリスト値が返ります。(配列やハッシュも、リストに展開されて返されます。) どちらの場合でも、勝手に別名やリファレンスが返されることはありません。戻値は常に値渡しです。 # ハッシュは return できない、とありましたが、もちろんできます。 ■配列とリストについて とかく同じ物と思われがちですが、これらは別物です。 例えば、それぞれをスカラーコンテキストで参照すると、配列は「要素数」が返るのに対し、リストでは「最後の要素」が返ります。 また、当然ながらリストには変数領域がないので、暗黙に配列へのリファレンスを引数に取る push 関数などには、リストは渡せません。 リストはあくまで、その場限りのものです。 ■無名配列、無名ハッシュについて これらは、変数の必要なしに、配列やハッシュの中身をメモリ上に生成するものです。 無名配列は   [ リスト ] 無名ハッシュは { リスト } として、生成します。 これらの値は、それぞれ「配列へのリファレンス」「ハッシュへのリファレンス」です。 > 配列やハッシュの要素に、別の配列やハッシュを入れる というのは、この無名**を使います。(つまり、配列などの実体は入れられません。) 例えば、4×3の2次元配列は、次のように作ります。   my @a = ( [0,1,2,3],[4,5,6,7],[qw(a b c d)] ); 各要素を見るときは、   foreach $row (@a) {     foreach $val (@$row) {       print "$val ";     }     print "\n";   } とか、   foreach $r (0..2) {     foreach $c (0..3) {       print "$a[$r][$c] ";     }     print "\n";   } とします。 ■No.4 の補足について タイプミスかもしれませんが、   sub subroutine {     my $sch = $_[0];     my $arr = @{ $_[1] };     my $hsh = %{ $_[2] };   } これではダメです。 やるなら、   sub subroutine {     my $sch = $_[0];     my @arr = @{ $_[1] };     my %hsh = %{ $_[2] };     $arr[0] = …     $hsh{AAA} = …   } とするか、   sub subroutine {     my $sch = $_[0];     my $arr = $_[1];     my $hsh = $_[2];     $arr->[0] = …     $hsh->{AAA} = …   } とします。 分からない部分は補足してください。

関連するQ&A

  • Perlのクラス(*.pm)からuseする側の*.cgi内ののスカラやハッシュ、配列の参照は可能でしょうか?

     Perlのクラス(*.pm)からuseする側の*.cgi内ののスカラやハッシュ、配列の参照は可能でしょうか? いろいろなサーバに対応させやすくするため 1行目(Perlのパス)や各種モジュールのパスや設定情報を*.cgiに書いてプログラム本体は*pmに置きたいのです。 それとももっといい方法がございますでしょうか。  教えて!ください。

    • ベストアンサー
    • Perl
  • リファレンスをサブルーチンの戻り値にしてもOKですか?

    ■ サブルーチン内部で処理した結果を格納した、配列、ハッシュ、スカラーなどのデータを戻り値として利用する必要があります。その場合、どうするのが標準的なやり方でしょうか? ■ return (配列へのリファレンス, ハッシュへのリファレンス, スカラー); などとやってしまっても問題はないでしょうか? ■ 下のプログラムを試したところ、予想に反しちゃんと 「31415」と表示されました。 #!/usr/bin/perl -w sub subroutine{ my @a = (3, 1, 4, 1, 5); return \@a; } my $b = subroutine{}; print @$b; ■ サブルーチン内部で使用した変数へのリファレンスをサブルーチン 外で使っていいのだろうか? サブルーチンの処理が終了した時点でサブルーチン内部で使用した 変数はメモリーから消去されるのかと思ったものですから。

    • ベストアンサー
    • Perl
  • サブルーチンの引数としてハッシュを渡したい

    ハッシュを引数として受け取り、そのハッシュの内容を csv形式に変換し出力するというサブルーチンを作っています。 ハッシュのキー名は固定なのですが、 引数として渡すハッシュの名前がバラバラの場合、 それを引数としてうけとることは可能なのでしょうか? また、どのように受け取ればいいでしょうか?

    • ベストアンサー
    • Perl
  • Perl・DBIでの汎用selectサブルーチンを作成するには?

    Perl・DBIで、select文発行のサブルーチンを作成していますが、未熟なため、完成できません。 呼び出し側では、下の記述のように、サブルーチンの引数として、SQL文を渡し(SELECT系)、戻り値として、SELECTされた結果を取得したい(配列もしくは、ハッシュで)と思っております。 もし、参考にできる、サイト・ サンプルサイト等のご紹介でも、結構ですので、ご教授くださればと思います。(処理の流れ等の箇条書きでもかまいません。) -------------------------------------------- # 呼び出し側(メインルーチン) $name;#テンプレート置換変数  $age; #テンプレート置換変数 my $sql =<<"EOQ"; # この抽出select文はその都度変わる。 select NAME,AGE from EMP EOQ my @row = &do_select($sql); $name = $row[0]; $age = $row[1]; もしくは、 $name = $hash_ref->{NAME}; $age = $hash_ref->{AGE}; のような記述で代入。 # テンプレートを読み込んで、置換処理で代入 ※幾分省略しています。 <table> for(){# SELECT分の結果の行数分繰り返し処理。 <tr>  <td>$name</td>  <td>$age</td> </tr> } </table> my $dbh = DBI->connect($dbhost, $dbuser, $dbpass) || die $dbh::errorstr; ##### select発行サブルーチン ####### sub do_select{ my $sth; my $rv; my @row; # 戻り値(フィールドが入る) my %dbhash; # 戻り値はこちらかな? my $sql = shift(@_); # select文 $sth = $dbh->prepare("$sql"); $rv = $sth->execute || die $sth->errstr; while($hash_ref = $sth->fetchrow_hashref){      # print "$hash_ref->{TITLE}<br>"; # ここに、何かの処理が入る } return @row; }

    • ベストアンサー
    • Perl
  • <Perl>参照配列の出力に失敗する。

    <Perl>参照配列の出力に失敗する。 お世話になります。 配列の出力部で以下のエラーが出力されます。 Use of uninitialized value in print at test2.pl line 12. -----コーディングは以下の通りです。----- #!C:\perl use strict; use warnings; my @l = (); #----------- #GetDataへCSVファイル名と、格納用配列を渡す #----------- my $cnt = &GetData("test.csv", \@l); print "COUNT -> ".$cnt; for(my $i=0; $i < $cnt; $i++){ print $l[$i]; } ################################################################## # 概   要:指定したCSVファイルをオープンしCSVデータを配列に取得する。 # パラメータ:ファイル名, CSVデータ格納用配列 # 戻 り 値:データ取得件数 ################################################################## sub GetData { my ($f, @bf) = @_; my $rcnt = 0; print "FILE NAME -> ".$f."\n"; if ( open(FP, "<${f}") ){ print "FILE OPEN -> success.\n"; @bf = split(/,/, <FP>); close(FP); $rcnt = @bf; print "CSV GET COUNT -> ".$rcnt."\n"; } return $rcnt; } -----実行結果は以下の通りです。----- D:\>perl test.pl FILE NAME -> test.csv FILE OPEN -> success. CSV GET COUNT -> 5 Use of uninitialized value in print at test2.pl line 12. Use of uninitialized value in print at test2.pl line 12. Use of uninitialized value in print at test2.pl line 12. Use of uninitialized value in print at test2.pl line 12. COUNT -> 5 -----CSVファイルの内容は以下の通りです。(ファイル名:test.csv)----- あいうえお,かきくけこ,さしすせそ,たちつてと,なにぬねの 配列の要素数が取れているので、配列内にデータは格納されているとは思っています。 出力方法をどのように正せばよいがご教示お願い致します。

    • ベストアンサー
    • Perl
  • コンパイラの作成

     皆さんのお力を貸してください.  現在, Java 言語を用いてコンパイラを作成しているのですが, 関数の引数として 1 次元配列を渡す方法 ( 配列の要素全体のコピーを渡すのではなく配列の先頭の番地を渡す方法 ) と参照渡しのプログラム記述方法が解らず悩んでおります.  何卒ご教授お願いいたします.

  • サブルーチンの返値に配列のハッシュ

    いつもお世話になっております。 HTML::Templateを使用する為、サブルーチンの返値に配列のハッシュを入れたいと思っていますが、うまくいきません。 また、myの使い方が分からず、返値までの方法も若干気になります。 よろしくお願い致します。 use HTML::Template; @loop = &loop_make('aa<>ab<>ac','ba<>bb<>bc','ca<>cb<>cc'); my $template = HTML::Template->new(filename=>'sample.html'); $template->param(loop=>\@loop); print "Content-Type: text/html\n\n"; print $template->output; exit; sub loop_make{ @aaa = (); foreach $xxx (@_) { ($one,$two,$three) = split(/<>/,$xxx); push @loop, { one => $one, two => $two, three => $three }; } return \@aaa; }

  • ハッシュのリファレンスを用いた処理

    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ではどんな時変数宣言は必要ですか?

    Perl初心者です。 マニュアル本を見ると、Perlでは特に変数を宣言しなくても扱えるようになっていますよね。 今まで幾つか自作CGIプログラムを作ってきたのですが、一度も my や localといった変数宣言を使った事がありません。 プログラム自体は正常に稼働しているので今まで全く無視していたのですが、こちらのPerlカテゴリの質問などを参照させていただいていると、皆さん必ず変数を my で宣言してらっしゃいます。 これは行った方がよいものなのですか? 宣言する事のメリット、宣言しない事のリスク、もしくはしたほうが良い場合、しない方が良い場合等を教えてください。とりあえず、サブルーチン内で宣言すると他のサブルーチンでは使えないらしい、という事だけは朧気に… よろしくお願いします。

    • ベストアンサー
    • Perl
  • Perlのサブルーチンの引数引継ぎ?

    こんにちは。 Perlの引数について質問です。 サブルーチンに引数を渡し、サブルーチンの中で他のサブルーチンをよんでいます。 すると引数を渡していないサブルーチンにまで引数が与えられてしまっているようです。 @_で受け取ると引数が渡されてしまい、$_[0]だと渡されずにすみます。 これはなぜなのでしょうか?Perlには引数を引き継ぐルールでもあるのでしょうか? 以下、サンプルです。 -------------------------------- &test('引数です'); sub test { &test2; } sub test2 { (my $hoge) = @_; } -------------------------------- $hogeに「引数です」が入ります。 &test2;を&test2();とすると大丈夫です。

    • ベストアンサー
    • Perl