Perl/制御構造

出典: フリー教科書『ウィキブックス(Wikibooks)』

プログラミング > Perl > 制御構造

この項目では、Perlの制御構造について説明します。

目次

[編集] ループ

以下の説明で、EXPRは式、BLOCKはコードブロック、VARは変数、LISTはリスト、LABELはラベルを示します。 また、大カッコ([])で囲まれたものは省略可能です。

[編集] for

構文:

[ LABEL ] for ( [ EXPR ]; [ EXPR ]; [ EXPR ] ) BLOCK

繰り返し(ループ)処理のもっとも一般的な構文です。 カッコの中に3つの式をコンマで区切って記述します。いずれも省略可能で、すべて省略した場合は無限ループとみなされます。

最初のEXPRは初期化式です。ループの開始時に1回だけ評価されます。主にループ変数の初期化に使われます。

次のEXPRは条件式です。BLOCKが実行される前に毎回評価され、偽となった時点でループは終了します。 この式が最初から偽だった場合、BLOCKは1回も実行されません。

最後のEXPRは継続式です。BLOCKが実行された後に毎回評価されます。主にループ変数を変化させるのに使われます。

for ( $i = 0; $i < 5; $i++ ) { print "Hello $i\n"; }

上の例の実行結果は以下のようになります:

Hello 0
Hello 1
Hello 2
Hello 3
Hello 4

このプログラムの動作を説明すると、次のようになります:

  1. $i = 0が評価され、ループ変数$iが初期化されます。
  2. $i < 5が評価されます。真であればブロックが実行され、文字列が出力されます。偽であればその時点でループを終了します。
  3. $i++が評価され、$iの値が1増加します。
  4. 2と3を繰り返します。

次の例はユーザから入力された数値を合計し、その値を出力するプログラムです('q'が入力されると終了):

$total = 0;
for ( print 'input>'; ( $input = <> ) !~ /^q/i; print 'input>' ) { $total += $input; }
print "total: $total\n";

[編集] while, until

構文:

[ LABEL ] while ( EXPR ) BLOCK [ continue BLOCK ]
[ LABEL ] until ( EXPR ) BLOCK [ continue BLOCK ]

whileは、EXPRが真である間BLOCKを繰り返し実行します。 untilは、EXPRが偽である間BLOCKを繰り返し実行します。

つまり、 while ( EXPR ) は until ( not EXPR ) と等価です。

for文の例と同等のものは次のようになります:

$i = 0;
while ( $i < 5 ) {
    print "Hello $i\n";
    $i++;
}
$i = 0;
until ( not $i < 5 ) {
    print "Hello $i\n";
    $i++;
}

ただし、これらはループ制御コマンドが使用された場合、for文と厳密には等価ではありません。 continueブロックを設けることで、for文の継続式と等価に扱われるコードを記述できます。

$i = 0;
while ( $i < 5 ) {
    print "Hello $i\n";
} continue {
    $i++;
}

[編集] foreach

構文:

[ LABEL ] foreach [ VAR ] ( LIST ) BLOCK [ continue BLOCK ] 

リストの値を順番にVARに代入し、BLOCKを実行します。 VARはループ内のlocal変数とみなされるので、プログラムの他の場所で使用していても問題ありません。 VARを省略した場合、local変数の$_が使われます。 ループ内をスコープとするmy変数を使用したい場合、次のようにします:

foreach my $i ( 0..4 ) { print "Hello $i\n"; }

これもfor文の例と同等ですが、while文、until文の例と同様に厳密には等価ではありません。 foreachにもcontinueブロックを設けることが出来ます。

foreachは実のところforの同義語であり、相互に置き換えることが出来ます。 一行プログラム(ワンライナー)などでは、foreachとしてforを使うことがしばしばあります。

[編集] 条件分岐

[編集] if, elsif, else, unless

構文:

if ( EXPR ) BLOCK [ elsif ( EXPR ) BLOCK [ elsif ... ] ] [ else BLOCK ]
unless ( EXPR ) BLOCK [ elsif ( EXPR ) BLOCK [ elsif ... ] ] [ else BLOCK ]

条件分岐のための構文です。

ifは、EXPRが真であればBLOCKを実行します。 unlessは、EXPRが偽であればBLOCKを実行します。 つまり if ( EXPR ) は unless ( not EXPR ) と等価です。

elsifは、先に置かれたif/unless/elsifのBLOCKが実行されなかった場合にEXPRを評価し、真であればBLOCKを実行します。 elsifは複数設けることが出来ます。

unlessとelsifを組み合わせると、分岐の判断基準が不統一になって読解性が良くありません。 elsifが必要な場合は、 unless ( EXPR ) ではなく if ( not EXPR ) を使った方が良いでしょう。

elseは、先に置かれたif/unless/elsifのBLOCKが実行されなかった場合にBLOCKを実行します。

$a = 5;
if ( $a > 1 ) { print '$aの値は1より大きい'; }
$a = 5;
unless ( $a <= 1 ) { print '$aの値は1より大きい'; }
$a = 5;
if ( $a > 1 ) {
 print '$aの値は1より大きい';
} else {
 print '$aの値は1以下';
}
$a = 5;
if ( $a > 3 ) {
 print '$aの値は3より大きい';
} elsif ( $a > 1 ) {
 print '$aの値は1より大きい';
} else {
 print '$aの値は1以下';
}

[編集] 文修飾子

for/elsif/elseを除く制御構文は、文修飾子としても使用できます。 一文のみのごく簡単な制御の場合はこちらのほうが簡潔で、英文のような見た目になります。

print "Good morning.\n" if 6 <= $hour and $hour < 12;

[編集] ループ制御コマンド

ループ制御コマンドと呼ばれていますが、BLOCKの中であれば(1度しか繰り返さないループとみなせるので)どこでも使えます。

ラベルを指定することで入れ子になったループの制御もできます。省略した場合、もっとも内側にあるループを指定したとみなされます。

[編集] last

即座にループから脱出します。continueブロックは実行されません。

OUTER: while ( 1 ) { #無限ループ
    $i = 0;
    INNER: while ( $input = <> ) {
        last       if $input =~ /^restart/; #INNERループを脱出
        last OUTER if $input =~ /^quit/;
        print "$i\n";
    } continue {
        $i++;
    }
}

[編集] next

残りの文をスキップし、次の反復に移ります。 ループ条件式は評価されます。continueブロック、for文の継続式も評価されます。

[編集] redo

残りの文をスキップし、反復をやりなおします。 ループ条件式は評価されません。continueブロック、for文の継続式も評価されません。

ヘルプ