こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

サブルーチンの使い方

以下のプログラムを解読中ですが、いまいち理解できません。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}

投稿日時 - 2008-06-16 15:27:56

QNo.4105111

すぐに回答ほしいです

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

実際にプログラムを使ってみると分かりやすいでしょうか。
ご質問にある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と似たような機能を提供しています。
以上ご参考になる部分があればと思います。

投稿日時 - 2008-06-18 02:46:58

お礼

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

投稿日時 - 2008-06-19 14:27:57

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(6)

ANo.6

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

投稿日時 - 2008-06-18 13:24:33

お礼

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

投稿日時 - 2008-06-19 14:26:13

ANo.4

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

投稿日時 - 2008-06-16 19:33:42

ANo.3

>この & の意味は、無名サブルーチンを表しています。
>引数に、sub {} というような無名サブルーチンを要求しています。

んなこたありません。
通常のサブルーチンのリファレンスも受け付けます。

use feature ':5.10';
sub foo() {
say "foo";
}

sub bar(&) {
my $proc = shift;
&$proc;
}

bar(\&foo);

投稿日時 - 2008-06-16 19:10:36

ANo.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 に足しています。

恐らく、このような説明では理解し難いと思うので、
リファレンス、無名サブルーチン、プロトタイプ、それぞれを調べることをおすすめします。

投稿日時 - 2008-06-16 17:43:18

お礼

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

いただいたキーワードで検索し、ドキュメントを熟読してみたところ、かなりイメージを具体化できました。ありがとうございました。

投稿日時 - 2008-06-19 14:29:34

ANo.1

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

投稿日時 - 2008-06-16 17:36:21

あなたにオススメの質問