• ベストアンサー

Perlの戻り値について

配列の戻り値が理解できていないのですが、 Perlで正しく動作させるためには どのように記述したら良いのでしょうか? 戻り値の動作を詳しく書いてある(出来れば図入りで) 本はありますか? 例) sub a { my @a = ('A'); return (@a, "B", 2); } my (@a, $b, $c) = &a; print "a=[@a] b=[$b] c=[$c]\n"; # a=[A] b=[B] c=[2] # これを期待していたが # a=[A B 2] b=[] c=[] # こちらになる

  • Perl
  • 回答数6
  • ありがとう数3

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

  • ベストアンサー
  • SE-1
  • ベストアンサー率57% (26/45)
回答No.1

#1 以下のようにしてご希望の結果が得られます。 #2 サブルーチン内外の @a は別物で、外の @a には戻り値のすべてが入ってしまいます。 #3 本ではないですが・・・過去の質問(リンク先)が参考になります。 # ------- 例1 ---------- use strict; sub a { my @a = ('A','C','D'); return (@a, "B", 2); } my @a = &a; my $c = pop(@a); my $b = pop(@a); print "a=[@a] b=[$b] c=[$c]\n"; # ------- 例2 ---------- use strict; sub a { my @a = ('A','C','D'); return (\@a, "B", 2); } my ($a, $b, $c)=&a; my $n=@{$a}-1; print "a=[@{$a}[0..$n]] b=[$b] c=[$c]\n";

参考URL:
http://oshiete1.goo.ne.jp/kotaeru.php3?q=1958086
mine_23
質問者

お礼

なるほど、リファレンスを使うことが普通ということですね。 ありがとうございます。 私は、 my ($a, $b, $c)=&test; my @aa = @$a; my @bb = @$b; で後は普通に配列で使おうと考えているのですが、 これでは何か不具合でもあるのでしょうか? 以下のテクニックはスライスする?で厳密にサイズを 取ってきていますが、リファレンスの場合は、 厳密にサイズを取得する必要があるのでしょうか? my $n=@{$a}-1; print "a=[@{$a}[0..$n]] b=[$b] c=[$c]\n"; 理解不足で申し訳ございません。

その他の回答 (5)

  • kapura
  • ベストアンサー率50% (48/95)
回答No.6

すでにお気づきかもしれませんが、サブルーチンの戻り値として配列とスカラーの混合したものを返したい場合にどのようにすればいいのかという問題で注目すべきなのは、サブルーチンの書き方というより、むしろそのサブルーチンを使う部分 (代入文) です。 サブルーチンの戻り値を書くreturn文のところだとかに限らず、一般に配列を配列 (リスト) の要素にしたつもりで書いても、要素にしたつもりの配列は展開されて全体が連なった1つの配列と解釈されてしまうということを認識するのがポイントだと思います。これはPerlでは配列の要素に成り得るのが、スカラーだけということから来る帰結でしょう。つまり、サブルーチンの戻り値の書き方というところを難しく考える必要はなくて、return文などでいくら配列を含むリストを書いても、単純に1つの配列を返す場合と同じことになると、シンプルに考えればいいと思います。 質問で示されたサブルーチンaは配列@aを要素にもつ配列を返しているのではなくて、要素にしたつもりの配列がスカラーの並びに展開され、全体として1つの配列を返しているわけです。(@a, "B", 2)は(@aの要素の並び, "B", 2)ということです。結果として、そのサブルーチンを使用している my(@a, $b, $c) = &a; という代入文は my(@a, $b, $c) = ("A", "B", 2); としたことと同じことになるわけです (もちろんダブルクォートの代わりにシングルクォートでもいいです,より厳密に言えば右辺の&aはリストコンテキストで解釈されるために("A", "B", 2)となっていて、例えば左辺がmy $dとかだったら3という風にスカラーコンテキストで解釈されます)。 大胆に言えば、returnで返すものが(\@a, "B", 2)のようにリファレンスを使ったものでなく、(@a, "B", 2)を返そうとするコードを書いている時点で変だと感じるべきではないか思います。もちろん、1つの配列を返すのと同じことをしているのだと承知の上でそう書いているのであればいいのですが。また、my(@a, $b, $c) = &a; というような代入文を書いている時点でも変だと感じるべきだと思います。なぜなら、このように書いた場合、サブルーチンaの返すものがスカラーだろうが配列だろうが、$bと$cには何も代入されない (undef) わけで my @a = &a; my($b, $c); などと書いたのと同じだと認識しているのであればいいですが、勘違いの元になる書き方でしょう。 つまり、入門書の代入操作と行ったところを確認すればわかると思いますが、代入文を my(変数のコンマ区切り) = 配列 (あるいはスライスやリスト) という風に書くのであれば、No.3で説明されているように左辺でスカラー変数を先に書かないと変なわけです。必然的に、サブルーチンの戻り値の順序も変更する必要が出てくるわけです。どうしてもサブルーチンを変更したくないのであれば、代入文のところを変更して、popやスライスを使うとか工夫をする必要がでてくるわけです。リファレンスを使う方法もあるわけですが、その場合もNo.4で説明されているように実体を扱っていることを意識するというのはありますが、あまり難しく考えず単純に配列やハッシュなどをスカラー化した (それによって配列の要素にできるようになったりする) とまず考えればいいと思います。心配であれば、my @aa = @$a;のように@aの内容を@aaにコピーして、それ以降@aa扱うようにすれば、@aaを変更しても@aには影響しないので全く難しく考える必要はないと思います (@aのことは忘れて@aaを扱えばいい)。書籍としては、ULTIMATE PerlやEffective Perlなどが、取っ付きやすい問題集といった感じで勘違いを減らすのにいいと思います。 http://www.ascii.co.jp/books/detail/4-7561/4-7561-3057-7.html

  • SE-1
  • ベストアンサー率57% (26/45)
回答No.5

>リファレンスの場合は、厳密にサイズを取得する必要があるのでしょうか? my $n=@{$a}-1; print "a=[@{$a}[0..$n]] b=[$b] c=[$c]\n";     ↓ print "a=[@$a] b=[$b] c=[$c]\n"; 同じ結果になりました。あえてサイズを取得しなくてもいいみたいですね。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.4

>やはり、リファレンスが一般的なようですね。 はい、普通に、配列を関数の引数にすると、展開されてしまうので、 個別に配列として取り扱うのは、リファレンスにするのが普通です。 >リファレンスの注意しておかないといけない点は何かあるのでしょうか? 既にご理解されている通り、リファレンスの場合、実体をいじっているということを頭に入れておく必要があります。 >引数でリファレンスを使うと呼び出し元の内容が変わる危険があることは理解できましたが、戻り値の場合はどうなるのでしょうか? 同様だと思います。(サブルーチンで作られた実体をいじっているという意識が必要) C等と違って、Perlでは、参照がある限り、解放されるということがないので、どこで作られた値でも同じです。 >my @aa = @$a; >で後は普通に配列で使おうと考えているのですが、これでは何か不具合でもあるのでしょうか? @aaには、コピーが作成されるので、普通に配列として扱って問題ないです。 >以下のテクニックはスライスする?で厳密にサイズを取ってきていますが、リファレンスの場合は、厳密にサイズを取得する必要があるのでしょうか? 質問の意図するところがよくわかりませんが、 print "a=[@array]\n"; print "a=[@$ref]\n"; は、同じです。 @リファレンス で、デリファレンスしたものは、普通の配列と同様に扱えると思います。 勘違いコメントだったらすみません。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.3

my (@a, $b, $c) = &a; の時最初の配列が全てのデータを取り込んでしまいます。 並びを変更して return ("B", 2, @a); にして my ($b, $c, @a) = &a; にするのが簡単かと思います。

mine_23
質問者

お礼

配列の戻り値が1つの場合は、popと同様に、 これを使うと簡単にできますね。 初めてしりました。 ありがとうございます。 やはり、リファレンスが一般的なようですね。 あまり、リファレンスを使っていないのですが、 リファレンスの注意しておかないといけない点は 何かあるのでしょうか? 引数でリファレンスを使うと呼び出し元の内容が変わる 危険があることは理解できましたが、戻り値の場合は どうなるのでしょうか?

  • SE-1
  • ベストアンサー率57% (26/45)
回答No.2

お気づきとは思いますが、a が違う意味(サブルーチン、配列、リファレンス)で3箇所使われていますので、実際には違う名前にしてくださいね。

関連するQ&A

  • 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
  • リファレンスをサブルーチンの戻り値にしてもOKですか?

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

    • ベストアンサー
    • Perl
  • perlの構文がおかしいようです。

    構文は以下の通りです。IF文のところがおかしいようですが、どこに間違いがあるのか教えていただけないでしょうか。 sub ippack { my ($a, $b, $c, $d) = @_; return ($a << 24) | ($b << 16) | ($c << 8) | $d; } sub ipunpack() { my ($n) = @_; return (($n>>24)&0xFF,($n>>16)&0xFF,($n>>8)&0xFF,$n&0xFF); } open (IN,"<useIP.txt") while(my $input = <IN>) { if ($input =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+) ([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/){; my $n = &ippack($1,$2,$3,$4); my $m = &ippack($5,$6,$7,$8); $n = $n & $m; $m = ~$m & 0xFFFFFFFF; for(my $i = 0; $i <= $m; $i++) { print join(".", &ipunpack($n+$i))."\n "; } } if-else($input =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/);{ print "$input\n"; } print "\n"; }

    • ベストアンサー
    • Perl
  • perlでサブルーチンへの複数の配列渡し

    perlでサブルーチンに配列を渡しているのですが、 引数としている配列が1個の場合は問題ないのですが、 複数渡すと、第2引数以降が渡りません。 どの様にすれば上手くできますか。 例1 #!/usr/bin/perl @x1 = (14, 11, 5, 12, 8, 15); @x2 = (12, 10, 8, 9); print "main : @x1 \n"; &test(@x1); sub test { my (@arg1) = @_; print "sub : @arg1 \n"; } 結果 main : 14 11 5 12 8 15 sub : 14 11 5 12 8 15 例2 #!/usr/bin/perl @x1 = (14, 11, 5, 12, 8, 15); @x2 = (12, 10, 8, 9); print "main : @x1 \n"; print "main : @x2 \n"; &test(@x1, @x2); sub test { my (@arg1, @arg2) = @_; print "sub : @arg1 \n"; print "sub : @arg2 \n"; } 結果 main : 14 11 5 12 8 15 main : 12 10 8 9 sub : 14 11 5 12 8 15 12 10 8 9 sub : 引数1に全てが設定されて、引数2に設定されていない。

    • ベストアンサー
    • Perl
  • Perlのサブルーチンで連想配列(ハッシュ)を渡す

    Perlのサブルーチンで連想配列(ハッシュ)を渡す方法 -------------------------------------- $str=rep::replace(%A,$B,@C); -------------------------------------- sub refidrep ( \%\$\@ ){ my(%A,$B,@C)=(@_); } -------------------------------------- では、上手くいきませんでした。 どのようにしたら、連想配列をサブルーチンに渡せるのでしょうか? 分かる方いらっしゃいましたらご教授ください。

    • ベストアンサー
    • Perl
  • Perlのキャプチャ

    プログラム #!/usr/bin/perl my $str = "abc,def,ghi"; ($a,$b,$c) = $str =~ /(.*),(.*),(.*)/; print $a,"\n"; print $b,"\n"; print $c,"\n"; 実行結果 abc def ghi このようなプログラムで ($a,$b,$c) = $str =~ /(.*),(.*),(.*)/;は それぞれ$a,$b,$cにabc,def,ghiが入ります. キャプチャしたすべてを変数に入れるならこの方法ですが, defだけが欲しいのに変数を3つ用意する必要がないと思います. 間違った表記ですが, ($b) = $str =~ /(.*),(.*),(.*)/$2/; 2つ目にキャプチャした$2が変数$bに入るような表記は出来ないのでしょうか?

  • Perlで複数の値を返す良い方法はありますか?

    以下のように多重代入できるかと思って確かめましたが、 結果は以下の通りでした。 $a=[] $b=[20] 方法はいろいろとありそうですが、Perl苦手でわかりません。 sub test{ local $cc = ''; local $s = ''; $cc = 'AAAAA'; $s = 20; # return $cc, $s; } $a, $b = &test; print "\$a=[$a]\n"; print "\$b=[$b]\n"; exit; __END__

    • ベストアンサー
    • Perl
  • サブルーチンの戻り値

    すみません、教えてください。 サブルーチンの戻り値に、複数の配列を指定したいと思っています。 return(@data1,@data2,@data3,@data4); これら配列を戻り値として渡す時、4つの配列として渡す場合 サブルーチンを呼ぶ時はどのように記述すればよいでしょうか? それぞれ、配列のデータ量が違ったりしています。 やはり一度、一つの配列としてそれを区分していくやり方しかないですかね? よろしくお願いします。

    • ベストアンサー
    • Perl
  • Perlです。サブルーチンについて

    以下の文はあっていますでしょうか。 # サブルーチンを呼び出して引数は 3 とする。 # そして返ってきた戻り値を変数$aに代入せよ。 $a=&a(3); # サブルーチン名aせよ。 sub a{ # $_[0]が引数 3 となりプラス1して変数$bに代入せよ。 $b=$_[0]+1; # 変数$bの内容を戻り値として返せ。 return $b; } # 変数$aの内容を表示せよ。 print "$a";

    • ベストアンサー
    • Perl
  • 配列のコピー及び printの .と,の挙動の違い

    以下、Perlの仕様についてわからないことが2点あります。 1) 配列のコピーは実態をコピーするようですが、参照扱いになるのは引数で与えた時でしょうか? 2) 下の例で@aは 6という個数を返し、@bは 1bcという配列の中身を返します。printの.と,で挙動が変わる理由が知りたいです。 例) my @a = qw(1 2 3 a b c); my @b = @a; splice @b, 1, 3; print @a . "\n"; # 6 print @b , "\n"; # 1bc

    • ベストアンサー
    • Perl

専門家に質問してみよう