• ベストアンサー

サブルーチンの使い方

以下のプログラムを解読中ですが、いまいち理解できません。C言語の経験はあるのですが、Perl初心者のため、Perlの文法を中心に、以下のポイントについて教えてください。 (1)この関数で、引数が「&@」となっていますが、この&の意味は「サブルーチン」ということですか?? (2)2行目のmy ($block, @listin) = @_ で各$block, @listinに格納される値を教えてください。「@_」を調べてみたところ、「サブルーチンの引数を代入」とあるのですが、ここでは、map_block(&@)の&@が&blockと@litinに代入されるということですか??そもそも&@とは何でしょうか? (3)4行目のpush @listout, &$block() for (@listin) について、push関数を調べてみたところ、配列の最後尾に値を格納するということですが、&$block() for (@listin) の部分の意味がよくわかりません。どのような値が、配列listoutに格納されるのでしょうか? (解読中のプログラム) 1sub map_block (&@) { 2   my ($block, @listin) = @_; 3 my @listout = (); 4 push @listout, &$block() for (@listin); 5 return @listout; 6}

  • ny_cs
  • お礼率53% (17/32)
  • Perl
  • 回答数6
  • ありがとう数3

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

  • ベストアンサー
回答No.5

実際にプログラムを使ってみると分かりやすいでしょうか。 ご質問にあるmap_blockサブルーチンは、 @result = map_block {  length $_; } @list; のように使用することができます。 プロトタイプというのは、サブルーチンが受け取る引数の種類を設定できる仕組みです。 &はブロック、@はリストを意味します。&@ならば、第一引数がブロックで、第二引数がリストという意味です。上記の例ではまさしくそうなっていますね。 次にサブルーチンの中身ですが、上記の例で言いますと$blockには {  length $_; } というコードが入ります。これは(サブルーチンのリファレンスですので)後から実行することができます。 そしてお分かりのように、@listinには@listの要素が丸ごとコピーされます。次に push @listout, &$block() for (@listin); というコードは、次のコードと全く同じです。 for (@listin) {  push @listout, &$block(); } pushの後にforを書けるという、ただそれだけのことです。このような書き方は後置forなどと呼ばれます。 for (@listin)というループでは、ループが回るたびに@listinの要素が1つずつ$_に入っていきます。 そして$blockを呼び出しているので、先程の {  length $_; } が実行されます。これは$_に入っている文字列の長さを返します。さらに返された長さが、pushによって@listoutの末尾に追加されていきます。 まとめると、@listinのそれぞれの要素を$_に代入し、$_に対して何らかの操作を行って、その結果を@listoutに追加していっているわけですね。 最後に@listoutが返されて、見事処理結果を得られるわけです。 なお、このmap_blockサブルーチンはPerlの組み込み関数であるmapと似たような機能を提供しています。 以上ご参考になる部分があればと思います。

ny_cs
質問者

お礼

詳細な解説、誠にありがとうございました。いただいた解説を熟読し、さらに実際に、プログラムを実行してみて、かなりイメージが具体化できました。ありがとうございます。

その他の回答 (5)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.6

えっと.... さしあたり 5.8.8 ですが, プロトタイプにおける & は原則として「サブルーチンへのリファレンス」でないとダメです>#5. 「ブロックが書ける」とか「実はそのあとのコンマも省略できる」というのは, 「最初の引数のプロトタイプとして & が書かれている」場合の特殊事情のはず.

ny_cs
質問者

お礼

ありがとうございました。バージョンによって、動作が異なるのですね。参考になりました。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.4

プロトタイプの & はサブルーチンへのリファレンスを要求します. 無名サブルーチンは自動的にサブルーチンへのリファレンスに変換されるので OK. ただし, 先頭の & に限ってはただのブロックも受け付けるはずです.

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.3

>この & の意味は、無名サブルーチンを表しています。 >引数に、sub {} というような無名サブルーチンを要求しています。 んなこたありません。 通常のサブルーチンのリファレンスも受け付けます。 use feature ':5.10'; sub foo() { say "foo"; } sub bar(&) { my $proc = shift; &$proc; } bar(\&foo);

  • kodomo55
  • ベストアンサー率57% (8/14)
回答No.2

1. “プロトタイプ”を利用すれば、サブルーチンに渡す引数の数や型に制約を加えることができます。 この & の意味は、無名サブルーチンを表しています。 引数に、sub {} というような無名サブルーチンを要求しています。 2. &block ではなく、$block なので注意して下さい。 @_ は全ての引数が入っているとはご存知だと思います。 この場合は最初の要素が $block、残りの要素が、@listin に入ります。 &@ は先に少し触れましたが、プロトタイプというものです。 引数の数や型を指定することができます。 サブルーチンは引数の1つ目は無名サブルーチン、2つ目は配列ということを考慮します。 3. これは少し書き方を変えてみれば分かると思います。 for (@listin) { push @listout, &$block() } これと同じ意味になります。プロックの中身が1行なら、 今回の例のように見た目をすっきりさせて書くことができます。 それは、if 等でも可能です。 &$block の部分ですが、渡されたものは無名サブルーチンなので、 $block にリファレンスが作成されています。 リファレンスはショートカットの様なものなので、 使う為には、参照先の識別子($や@や&)を先頭に付ける必要があり、 &$block としてデリファレンスしています。 結果、@listin の要素1つずつにアクセスをして、その度に、$block の参照先のサブルーチン(無名サブルーチン)を実行し、得た結果を @listout に足しています。 恐らく、このような説明では理解し難いと思うので、 リファレンス、無名サブルーチン、プロトタイプ、それぞれを調べることをおすすめします。

ny_cs
質問者

お礼

ありがとうございます。そうなんです、プログラムのコードからはなかなかキーワードを特定できず、Perlのドキュメントの何を調べればよいのかあたりをつけるのにも大変苦戦しております。 いただいたキーワードで検索し、ドキュメントを熟読してみたところ、かなりイメージを具体化できました。ありがとうございました。

回答No.1

「Perl プロトタイプ」で検索

関連するQ&A

  • 特殊変数 $_ の使い方

    Perl初心者です。現在、海外の大学で勉強中なのですが、英語の壁にぶち当たり途方にくれ、こちらのサイトに駆け込みました。どうぞご協力よろしくお願いいたします。 (1)以下の関数で、特殊変数$_ が使われている部分がどこか?という問題があるのですが、よくわかりません。4行目の forの前かな?とは思ったりしたのですが、教えてください。 (2)また、この関数で、引数が「&@」となっていますが、この&の意味を教えてください。 (3)2行目のmy ($block, @listin) = @_ で各$block, @listinに格納される値を教えてください。 (4)この関数の呼び出し方を教えてください。 1sub map_block (&@) { 2   my ($block, @listin) = @_; 3 my @listout = (); 4 push @listout, &$block() for (@listin); 5 return @listout; 6}

  • サブルーチンからサブルーチンを呼び出す

    #平均を求める,サブルーチンを使用 @dat=(1,2,3,4,5,6,7,8,9,10); $mean=&mean(@dat); print "mean="; print $mean; sub mean{ $sum=&sum(@dat); $n=@dat; $mean=$sum/$n; return($mean); } sub sum{ for($i=0;$i<$n;$i++){ $sum+=$dat[$i]; } return($sum); } Perlを勉強し始めたのですがサブルーチンの所で分からない所があるので教えていただけませんか? mean関数(Perlではmeanルーチンなどと呼ぶべきでしょうか?)の中でsum関数を呼び出してデータの合計を$sumに代入したいのですが,この場合だとうまく代入されていないようなのですが,何がよろしくないのでしょうか?

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

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

    • ベストアンサー
    • 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】サブルーチンから多次元配列を戻したい

    【Perl】サブルーチンから多次元配列を戻したい サブルーチン内で作った2次元配列と1つの変数(例:@listと$i)をリターンしたいのですが、どのようにすれば良いでしょうか? ↓サブルーチン(calc) return (@list, $i); ↓メイン my $a = 12; my (@list, $i) = &calc($a); 間違っていると思いますが、現時点でのプログラムを一部書きました。 ご回答よろしくお願いします!

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

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

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

    サブルーチンについて教えて頂きたいのですが HTMLからPOSTされる複数のデータ(Key=A&値=B…)をkeyごとにサブルーチンの引数 として渡したいのですが、現在は「&ReadParse」を使って$inから値を取り出しています。 ただ数十個の値が一度にPOSTされる為、下記のコードをひたすら書く感じになってしまう のかな…と思ってお尋ねしております。 それから、サブルーチンからの戻り値を、フォームに(Key=A&値=B…)の感じで返したいのですが どうすればいいのでしょう。 @pairs = ($in{'val1'},$in{'val2'},$in{'val3'},$in{'val4'},$in{'val5'}); ($para1,$para2,$para3,$para4,$para5) = @pairs; $values = func($para1,$para2,$para3,$para4,$para5); 私自体、Perl初心者でわかっていない為、なにか方法があれば教えて下さい。宜しくお願いしますm(__)m

    • ベストアンサー
    • Perl
  • 力を貸してください

    7人の点数を格納する配列 tensu[i] の値をmain関数内で キーボード入力させ、その配列を関数 hairetsu() に引数 として与え、関数 hairetsu 内で配列の値をforと printfを 使い、表示させてください。

  • 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
  • 引数を受け取る@_について

    subプロシージャ(関数)の引数について教えていただきたいのですが,例えば, @data1=(1,2,3,4,5); @data2=(6,7,8,9,10); &stat::cov(@data1,@data2); などとすると,sub cov{}で@_という配列の中に一緒に格納されますよね。しかし私としては@data1に格納されているデータと@data2に格納されているデータを別の配列に渡したい(別の配列で受け取るようにしたい)のです。 考えた策としては sub cov{ my $n=@_; my $h=$n/2; for($i=0;$i<$h;$i++){ $x[$i]=shift(@_); } for($k=0;$k<$h;$k++){ $y[$k]=shift(@_); } (以下省略) のように,shift関数で1つずつずらして違う配列に格納していくという方法なのですが,これは@data1と@data2に格納されているデータ数が等しい場合で無いと使いものになりません。 指定した引数を@_以外の配列で受け取らせる方法などはないものでしょうか?ちなみにPerlはまだ初心者にも達していないド素人ですのであまりプロ志向のものは勘弁してください(それでもなければ仕方ありませんが、、、)。

    • ベストアンサー
    • Perl