Go to the first, previous, next, last section, table of contents.


複合実行文

Perl では、スコープが定義される実行文の列をブロックと呼んでいます。とき にはブロックは、そのブロックを含むファイルの単位で区切られ (この場合 require で読み込まれるか、プログラム全体ということになります)、また文字 列として区切られる場合もあります (eval される場合です)。

しかし、一般にはブロックは中括弧 (`{}') で区切られるのが普通です。この構 文上の構造を BLOCK と呼ぶことにします。

以下の複合実行文を、流れの制御のために使うことができます:

if (EXPR) BLOCK
if (EXPR) BLOCK else BLOCK
if (EXPR) BLOCK elsif (EXPR) BLOCK ... else BLOCK
LABEL while (EXPR) BLOCK
LABEL while (EXPR) BLOCK continue BLOCK
LABEL for (EXPR; EXPR; EXPR) BLOCK
LABEL foreach VAR (ARRAY) BLOCK
LABEL BLOCK continue BLOCK

C や Pascal と違って、文ではなく、BLOCK を使って定義されていることに注意 してください。これは中括弧が必須ということで、中ぶらりんの実行文が許され ないということです。中括弧を使わないで条件を書きたい場合には、方法がいく つかあります:

if (!open(FOO)) { die "Can't open $FOO: $!"; }
die "Can't open $FOO: $!" unless open(FOO);
open(FOO) or die "Can't open $FOO: $!";     # FOO or bust!
open(FOO) ? 'hi mom' : die "Can't open $FOO: $!";
                    # a bit exotic, that last one

はすべて同じことをします。

if 文は見た通りです。BLOCK は必ず中括弧で括られますから、if と else の対 応が曖昧になることはありません。if の代わりに unless を使えば、テストの 意味が逆になります。

while 文は、式が真である間 (評価結果が、空文字列、0、"0" のいずれかでな い間) ブロックを実行します。LABEL はあっても無くてもよく、もし存在する時 には、識別子にコロンを続けたものです。LABEL は、next、last、redo という ループ制御文が、ループを識別できるようにするものです (以下を参照)。 continue BLOCK があれば、C の for ループの 3 番目の部分のように、次に条 件が評価される直前に実行されます。ですから、(C の continue 文と同様に) たとえ next 文でループを進めるときにも、ループ変数のインクリメントが行な うことができます。

while を until で置き換えると、テストの意味が逆になりますが、繰り返しの 前に、条件が評価されることは変わりません。

if 文または while 文において、"(EXPR)" を BLOCK で置き換えることができ、 ブロックの最後に実行した文が真であれば、条件も真となります。(この機能は Perl 5 でも機能しますが、使わないようにしてください。"if BLOCK" の代わり に "if (do BLOCK)" とすればよいでしょう。)

C スタイルの for ループは、完全に対応する while ループと同じように動作し ます:

for ($i = 1; $i < 10; $i++) {
    ...
}

は、

$i = 1;
while ($i < 10) {
    ...
} continue {
    $i++;
}

と同じことです。

foreach ループは通常のリスト値で繰り返しを行ない、変数 VAR にそのリスト の値を順番に設定します。その変数は、(前もって my で宣言したのでなければ) 暗黙のうちにループ内にローカルとなり、ループを抜けると以前の値に戻ります。 キーワードの foreach は、実際にはキーワード for の同義語であり、読みやす さのために foreach を、簡潔さのために for を使い分けることが可能です。 VAR を省略すると、$_ に個々の値が順に設定されます。もし、ARRAY が (リスト値を返す式ではなく) 本物の配列の時には、ループの中で VAR を修正す ることによって、その時に対応している配列の要素自身を修正することができま す。例:

for (@ary) { s/foo/bar/; }

foreach $elem (@elements) {
    $elem *= 2;
}

for ((10,9,8,7,6,5,4,3,2,1,'BOOM')) {
    print $_, "\n"; sleep(1);
}

for (1..15) { print "Merry Christmas\n"; }

foreach $item (split(/:[\\\n:]*/, $ENV{'TERMCAP'})) {
    print "Item: $item\n";
}

BLOCK 自身は (ラベルが付いていても、いなくても) 意味的には、1度だけ実行 されるループと同じです。つまり、ブロックを抜けたり、再度実行したりするの に、ループ制御文が使えるということです。continue BLOCK はあっても無くて もかまいません。この構成は、case 構文を組み立てるのに便利です。

SWITCH: {
    if (/^abc/) { $abc = 1; last SWITCH; }
    if (/^def/) { $def = 1; last SWITCH; }
    if (/^xyz/) { $xyz = 1; last SWITCH; }
    $nothing = 1;
}

Perl には、公に switch 文は存在しません。同値なものが既にいくつもあるか らです。上にあげたものの他に、

SWITCH: {
    $abc = 1, last SWITCH  if /^abc/;
    $def = 1, last SWITCH  if /^def/;
    $xyz = 1, last SWITCH  if /^xyz/;
    $nothing = 1;
}

とも書けます。(これは、ループ制御「演算子」を式の中で使えることに気が付 けば、見た目ほど奇妙なものではありません。普通の C のコンマ演算子です。)

また、

SWITCH: {
    /^abc/ && do { $abc = 1; last SWITCH; };
    /^def/ && do { $def = 1; last SWITCH; };
    /^xyz/ && do { $xyz = 1; last SWITCH; };
    $nothing = 1;
}

とも書けますし、もう少し「正当な」switch 文のように整形すると:

SWITCH: {
    /^abc/      && do {
                        $abc = 1;
                        last SWITCH;
                   };

    /^def/      && do {
                        $def = 1;
                        last SWITCH;
                   };

    /^xyz/      && do {
                        $xyz = 1;
                        last SWITCH;
                    };
    $nothing = 1;
}

となりますし、

SWITCH: {
    /^abc/ and $abc = 1, last SWITCH;
    /^def/ and $def = 1, last SWITCH;
    /^xyz/ and $xyz = 1, last SWITCH;
    $nothing = 1;
}

や、醜くも

if (/^abc/)
    { $abc = 1 }
elsif (/^def/)
    { $def = 1 }
elsif (/^xyz/)
    { $xyz = 1 }
else
    { $nothing = 1 }

としてもよいでしょう。


Go to the first, previous, next, last section, table of contents.

検索式: