配列の戻り値が理解できていないのですが、
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=[] # こちらになる
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
なるほど、リファレンスを使うことが普通ということですね。
ありがとうございます。
私は、
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";
理解不足で申し訳ございません。
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-756 …
No.5
- 回答日時:
>リファレンスの場合は、厳密にサイズを取得する必要があるのでしょうか?
my $n=@{$a}-1;
print "a=[@{$a}[0..$n]] b=[$b] c=[$c]\n";
↓
print "a=[@$a] b=[$b] c=[$c]\n";
同じ結果になりました。あえてサイズを取得しなくてもいいみたいですね。
No.4
- 回答日時:
>やはり、リファレンスが一般的なようですね。
はい、普通に、配列を関数の引数にすると、展開されてしまうので、
個別に配列として取り扱うのは、リファレンスにするのが普通です。
>リファレンスの注意しておかないといけない点は何かあるのでしょうか?
既にご理解されている通り、リファレンスの場合、実体をいじっているということを頭に入れておく必要があります。
>引数でリファレンスを使うと呼び出し元の内容が変わる危険があることは理解できましたが、戻り値の場合はどうなるのでしょうか?
同様だと思います。(サブルーチンで作られた実体をいじっているという意識が必要)
C等と違って、Perlでは、参照がある限り、解放されるということがないので、どこで作られた値でも同じです。
>my @aa = @$a;
>で後は普通に配列で使おうと考えているのですが、これでは何か不具合でもあるのでしょうか?
@aaには、コピーが作成されるので、普通に配列として扱って問題ないです。
>以下のテクニックはスライスする?で厳密にサイズを取ってきていますが、リファレンスの場合は、厳密にサイズを取得する必要があるのでしょうか?
質問の意図するところがよくわかりませんが、
print "a=[@array]\n";
print "a=[@$ref]\n";
は、同じです。
@リファレンス
で、デリファレンスしたものは、普通の配列と同様に扱えると思います。
勘違いコメントだったらすみません。
No.3
- 回答日時:
my (@a, $b, $c) = &a;
の時最初の配列が全てのデータを取り込んでしまいます。
並びを変更して
return ("B", 2, @a);
にして
my ($b, $c, @a) = &a;
にするのが簡単かと思います。
配列の戻り値が1つの場合は、popと同様に、
これを使うと簡単にできますね。
初めてしりました。
ありがとうございます。
やはり、リファレンスが一般的なようですね。
あまり、リファレンスを使っていないのですが、
リファレンスの注意しておかないといけない点は
何かあるのでしょうか?
引数でリファレンスを使うと呼び出し元の内容が変わる
危険があることは理解できましたが、戻り値の場合は
どうなるのでしょうか?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Perl perlをバージョンアップしたら、今まで正常に動いていたプログラムが、エラーになってしまった 3 2022/10/05 15:44
- その他(プログラミング・Web制作) pythonのプログラムについての質問です。 1 2023/05/26 10:31
- Perl perlでリテラル値はメモリにどのように格納されているか? 1 2023/01/15 20:45
- JavaScript カラーミーショップのsectionループ内で、[引数][戻り値]ありの関数的な処理を行いたいです。 1 2022/05/07 19:39
- CGI perlで書いたcgiでsqliteの使い方を教えてください 2 2023/05/08 21:29
- Excel(エクセル) エクセルのイベントVBAを複数のシートで動かしたい 1 2022/12/07 16:55
- C言語・C++・C# C言語初心者 構造体 課題について 2 2023/03/10 19:48
- Perl perlの構文でカンマの意味が分からない 2 2022/10/30 01:53
- C言語・C++・C# C++のcinの動作 5 2023/02/26 00:13
- Visual Basic(VBA) Excel VBA マクロ ある列の最終行迄を参照し、別の列の空白セルに値を入力したいです 2 2023/03/05 02:44
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
Can't use string ("0") as an ...
-
サンプルの意味
-
アクティブセルから、A列最終行...
-
画面を強制的に再描画させる方法
-
どなたかこのプログラミングを...
-
ハッシュ検索はなぜ速い
-
乱数の桁数指定、または範囲指定。
-
アセンブラによるウェイト(WAIT...
-
VBのReturnの使い方
-
VBA for i=1 to lastrow
-
VBAでの一時停止と再開の方法
-
一意(ユニーク)かつ、ソート...
-
Dim flag(4) as boolean で配列...
-
Excel VBA ユーザーフォームの...
-
alarmの使用について
-
For文を使った九九表の作成
-
Perlは戻り値で、ハッシュや配...
-
「偶数・奇数の和」のフローチ...
-
UWSCの終了の仕方
-
EXCEL VBA(初心者)印刷ルー...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Can't use string ("0") as an ...
-
PerlでCSV形式のファイルの一部...
-
perlの引数が不安定になります。
-
perlの比較、ループの使い方に...
-
レキシカル変数について
-
画面を強制的に再描画させる方法
-
VBAでの一時停止と再開の方法
-
データベースでユーザーのパス...
-
VBのReturnの使い方
-
ループ7回目の悪役令嬢は、元敵...
-
UWSCの終了の仕方
-
Escキーを押すと、中断する時と...
-
エクセルの当番表を作っていま...
-
GIFアニメをループさせたくない
-
VBAで3秒だけ時間を止めたい
-
どなたかこのプログラミングを...
-
VBA for i=1 to lastrow
-
文字列を変数名として扱う方法
-
ハッシュ検索はなぜ速い
-
DOSコマンドのループ内のTIMEコ...
おすすめ情報