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

複合文

perl において、コマンド群を `{}' で囲むと 一つのコマンドとして扱うことができる。これをブロックと呼ぶ。

次の複合コマンドはフローコントロールのために用いる。

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 と違い、これらは文(statement)ではなく、 ブロックとして宣言されている点である。このため、{} が必要となる。 条件文を {} を使わずに書くためには、いくつか方法がある。 次の例は全て同じことをする。

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

if 文は単純である。ブロックは必ず {} で囲まれているので、 ifelse がどこにかかるかについて曖昧になることはない。 if の代わりに unless を使う場合、テストの結果が逆に扱われる。

while 文は expression が真(ヌル文字列や 0 でない)である間、 ブロックを実行する。ラベルをつけてもよい。ラベルをつける場合、 その識別子の後にコロンをつける。 ラベルはループコントロール文 nextlastredo の ループを指定する(identifies the loop)(以下の例を参照。)。 continue ブロックがあれば、条件文を再評価する直前に必ず実行される。 これは for ループの 3 番目の条件と同様である。 このため、たとえループが next 文を通じて続行される場合でも、 ループ変数のインクリメントを行うために用いることができる。 (C の continue 文と同様。)

whileuntil で置き換えると、 テストの結果が逆に扱われるが、条件テストはループの最初にも行われる。

if 文や while 文において、 (EXPR) をブロックで置き換えることができる。 この場合、条件はブロックの最後のコマンドの値が真ならば真となる。

for ループは それと対応する while ループと全く同様に動作する。

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

は次と同じである。

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

foreach ループは通常の配列値について、 順にその要素を変数にセットしながら繰り返しを行う。 変数は暗黙的にループにローカルで、ループを抜けると元の値に戻る。

実はキーワード foreachfor と全く同じものなので、 読み易さで foreach、簡潔さで for を使うことができる。

変数名を省略すると、各々の値は $_ にセットされる。 配列値が(配列値を返す expression ではなく)実際の配列の場合は、 ループの中で変数を変更することで配列要素を変更することができる。例えば:

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";
}

ブロックはそれ自体(ラベルがついていてもいなくても)が 一回だけ実行されるループと同じである。そこで、ブロックから抜けたり、 ブロックを再実行したりするのにループコントロール文を使うことができる。 continue ブロックもつけることができる。 このような構成は case 構造を記述するのに便利である。

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

同様のことを記述する方法がいくつかあるので、 perl には正式な switch 文はない。上の例に付け加えると、 次のようにも書ける。

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

または

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

または

foo: {
     /^abc/ && ($abc = 1, last foo);
     /^def/ && ($def = 1, last foo);
     /^xyz/ && ($xyz = 1, last foo);
     $nothing = 1;
}

さらには

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

実際にはこれらはすべて内部で switch 構造に最適化されるので、 perl は直接目的とする文へジャンプする。 だから一つの同じ単純なスカラー値を ==eq や 上のようなパターンマッチングでテストするかぎりにおいては、 elsif が 50 もあったりすると、 perl が不必要な文をたくさん実行するのではないか、という心配をする必要はない。 (もし、case ステートメントに最適化されているかどうかに興味があるなら、 -D1024 を用いて実行前にシンタックスツリーを表示させることができる。)


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