Caché WHILEコマンド
条件が真のときにコードを実行します。
重要
- 無限ループに注意してください。
- FOR ループは新しいレベルをスタックにプッシュします。 WHILE ループはスタック・レベルを変更しません。FOR ループをデバッグする場合
- シングル・ステップ・デバッグでは、FORとWHILEの違いがあります。
概要
WHILE expression,... {
code
}
パラメータ
- 式 テスト条件。カンマで区切られたテスト条件を1つ以上指定することができます。
- code 中括弧で囲まれた ObjectScript コマンドブロック。
説明
WHILEは式をテストし、式がTRUEと評価された場合、左中括弧と右中括弧の間のコード・ブロックを実行します。WHILEは、式の計算結果がTRUEである限り、コードのブロックを繰り返し実行できます。式が TRUE でない場合、括弧内のコード・ブロックは実行されず、中括弧 ( }) の直後にある次のコマンドが実行されます。
プログラマはWHILE無限ループを避けるように注意しなければなりません。 WHILE 1 {... ...は無限ループを実行するので、ループするコードはループを抜けるためにQUITを発行しなければなりません。
左中括弧または右中括弧は、それ自身のコード行に現れることもあれば、コマンドと同じ行に現れることもあります。開中かっこや閉中かっこは1列目に表示されることもあります。中括弧は、入れ子になったコード・ブロックの先頭と末尾を示すためにインデントすることが推奨されます。中括弧の前後にスペースは必要ありません。右中括弧では、スペースは必要ありません。右中括弧は、スペース、タブ、または改行で後続のコマンドと区切る必要があります。
括弧内のコードブロックには、1 つまたは複数の ObjectScript コマンドと関数呼び出しが含まれます。ブロックは複数行にまたがることもあります。コードブロック内では、インデント、改行、スペースを使用できます。このコードブロック内のコマンドのコマンドと引数は、1 つ以上のスペースまたは改行で区切ることができます。
パラメータ
expression
ブール値のテスト条件。これは、単一の式、またはコンマで区切られた式のリストの形式を取ることができます。Caché が式を TRUE と評価すると、WHILE ループが実行されます。通常、式は x < 10 や " apple" = " apple" などの条件テストですが、0 以外の数として評価される値はすべて TRUE になります。", " 7dwarves" はすべて TRUE と評価されます。ゼロの値はすべて FALSE と評価されます。
式のリストに対して、Caché は各式を左から右の順に計算します。0 と評価される式があると、計算が停止します。式の右側にある値が FALSE の式は、検証またはテストされません。
すべての式が 0 以外の値に評価されると、Caché は WHILE ループ・コード・ブロックを実行します。式の計算結果が TRUE である限り、Caché は WHILE ループを繰り返し、各ループの先頭で式をテストします。いずれかの式が FALSE と評価された場合、Caché は、WHILE が括弧を閉じた後のコードの次の行を実行します。
代表例
次の例は、WHILEループを指定された回数実行します。これはループ・テスト式を実行しています:
/// d ##class(PHA.TEST.Command).Mainloop()
ClassMethod Mainloop()
{
SET x=1
WHILE x<10 {
WRITE !," Looping",x
SET x=x+1
}
WRITE !,"DONE"
QUIT
}
DHC-APP>d ##class(PHA.TEST.Command).Mainloop()
Looping1
Looping2
Looping3
Looping4
Looping5
Looping6
Looping7
Looping8
Looping9
DONE
以下の例では、2つの式テストを実行します。2つのテストはカンマで区切られています。両方のテストの結果が真の場合、WHILEループが実行されます。その結果、これらのプロシージャはリスト内のすべての項目を返すか、リスト内の項目の指定されたサンプル・サイズを返します:
/// d ##class(PHA.TEST.Command).TestWhile()
ClassMethod TestWhile()
{
SET mylist=$LISTBUILD("a","b","c","d","e")
SET ptr=0,sampcnt=1,sampmax=4
WHILE 1=$LISTNEXT(mylist,ptr,value),sampcnt<sampmax {
WRITE value," はい 項目 ",sampcnt,!
SET sampcnt=sampcnt+1
}
IF sampcnt<sampmax {
WRITE "これは配列全体の"
}
ELSE {
WRITE "これは",sampcnt-1, "配列項目 "である。
}
}
DHC-APP>d ##class(PHA.TEST.Command).TestWhile()
a はい 項目 1
b はい 項目 2
c はい 項目 3
これは3つの配列項目である
/// d ##class(PHA.TEST.Command).TestWhile1()
ClassMethod TestWhile1()
{
SET mylist=$LISTBUILD("a","b","c","d","e")
SET ptr=0,sampcnt=1,sampmax=10
WHILE 1=$LISTNEXT(mylist,ptr,value),sampcnt<sampmax {
WRITE value," はい 項目 ",sampcnt,!
SET sampcnt=sampcnt+1
}
IF sampcnt<sampmax {
WRITE "これは配列全体の"
}
ELSE {
WRITE "これは",sampcnt-1, "配列項目 "である。
}
}
DHC-APP>d ##class(PHA.TEST.Command).TestWhile1()
a はい 項目 1
b はい 項目 2
c はい 項目 3
d はい 項目 4
e はい 項目 5
これは配列全体である
WHILE FOR
FOR や WHILE を使用して同じ操作を実行することも可能です。つまり、イベントによって実行がループから抜けるまでループします。しかし、どちらのループ構造を使用するかは、コード・モジュール上のシングル・ステップ・デバッグの実行に影響を与えます。
FOR ループは新しいレベルをスタックにプッシュします。 WHILE ループはスタック・レベルを変更しません。FOR ループをデバッグする場合、FOR ループ内部からスタックをポップすることで、FOR コマンドが構築された直後からシングル・ステップ・デバッグを継続できます。WHILE ループをデバッグする場合、BREAK" C" GOTO または QUIT 1 を発行してもスタックはポップされないため、WHILE コマンドが終了してもシングル・ステップ・デバッグは継続されません。残りのコード実行は中断されません。
WHILE DO WHILE
WHILEコマンドはループを実行して式をテストします。 DO WHILE コマンドは、ループを実行してから式をテストします。
WHILE CONTINUE
WHILEコマンドのコード・ブロック内でCONTINUEコマンドに遭遇すると、実行は直ちにWHILEコマンドにジャンプして戻ります。その後、WHILE コマンドは式のテスト条件を計算し、その計算に基づいてコード・ブロック・ループを再実行するかどうかを決定します。このように、CONTINUE コマンドはコードブロックの右括弧に到達するのと全く同じ効果を実行に与えます。
WHILE, QUIT, RETURN付き
コード・ブロック内のQUITコマンドは、次の例に示すように、WHILEループを終了し、右中括弧の後のコマンドに実行を移します:
/// d ##class(PHA.TEST.Command).Testloop()
ClassMethod Testloop()
{
SET x=1
WHILE x < 10
{
WRITE !," ,x
QUIT:x=5
SET x=x+1
}
WRITE !,"
}
このプロシージャは、Looping1 から Looping5 までを書き込み、DONE に書き込みます。
DHC-APP>d ##class(PHA.TEST.Command).Testloop()
WHILEコード・ブロックは入れ子にすることができます。つまり、WHILE コード・ブロックには別の制御フロー・ループを含めることができます。内部的に入れ子になったループの QUIT は、内部ループから次の閉じた外部ループにジャンプします。これを次の例に示します:
/// d ##class(PHA.TEST.Command).Nestedloops()
ClassMethod Nestedloops()
{
SET x=1,y=1
WHILE x<6 {
WRITE "外部ループ ",!
WHILE y<100 {
WRITE "内部ループ "
WRITE " y=",y,!
QUIT:y=7
SET y=y+2
}
WRITE "回答外部ループ x=",x,!!
SET x=x+1
}
WRITE "
}
DHC-APP>d ##class(PHA.TEST.Command).Nestedloops()
外部ループ
内部ループ y=1
内部ループ y=3
内部ループ y=5
内部ループ y=7
回答外部ループ x=1
外部ループ
内部ループ y=7
回答外部ループ x=2
外部ループ
内部ループ y=7
回答外部ループ x=3
外部ループ
内部ループ y=7
回答外部ループ x=4
外部ループ
内部ループ y=7
回答外部ループ x=5
RETURN は常に現在のルーチンを終了するか、呼び出し元のルーチンに戻るか、 呼び出し元のルーチンなしでプログラムを終了します。RETURN の動作は、コード・ブロックから発行されても発行されなくても、常に同じです。
WHILE GOTOの場合
コード・ブロック内の GOTO コマンドは、ループ外のラベルに実行を指示し、ループを終了させることができます。コードブロック内の GOTO コマンドは、同じコードブロック内のラベルに実行を向けることができます。コードブロックは、ループ外のラベルに実行を指示し、ループを終了させることができます。
GOTO コマンドは、他のコード・ブロック内のタグに実行を指示してはいけません。このような構成を実行することは可能ですが、入力コード・ブロックのテスト条件を破壊するため、「不正」と見なされます。
GOTOの以下の形式は合法です:
/// d ##class(PHA.TEST.Command).TestWhileGOTO()
ClassMethod TestWhileGOTO()
{
mainloop ; ブロックの外に出る
WHILE 1=1 {
WRITE !,"無限WHILEループ"
GOTO label1
WRITE !,"これは、"
}
WRITE !,"これは、"
label1
WRITE !,"label1に入り、"
}
DHC-APP>d ##class(PHA.TEST.Command).TestWhileGOTO()
無限WHILEループ
label1に入り、終了する
/// d ##class(PHA.TEST.Command).TestWhileGOTO1()
ClassMethod TestWhileGOTO1()
{
mainloop ; 同じブロック内の別の場所に移動する
SET x=1
WHILE x<3 {
WRITE !,"WHILEループの"
GOTO label1
WRITE !,"これは、"
label1
WRITE !,"GOTOそれ以降はまだWHILEループの中である。"
SET x=x+1
WRITE !,"x=",x
}
WRITE !,"WHILEループ完了"
}
DHC-APP>d ##class(PHA.TEST.Command).TestWhileGOTO1()
WHILEループの場合
GOTOWHILEループの中にある
x=2
WHILEループの場合
GOTOWHILEループの中にある
x=3
WHILEループ完了
/// d ##class(PHA.TEST.Command).TestWhileGOTO2()
ClassMethod TestWhileGOTO2()
{
mainloop ; 内部から外部へ入れ子になったブロックは、次のようになる。
SET x=1,y=1
WHILE x<6 {
WRITE !,"外部ループ",!
SET x=x+1
label1
WRITE "外側ループの繰り返し ",x-1,!
WHILE y<4 {
WRITE !," 内部ループの繰り返し ",y,!
SET y=y+1
WRITE " に戻る。
GOTO label1
WRITE " これは、",!
}
WRITE "内部ループ完了",!
}
WRITE "すべて完了"
}
DHC-APP>d ##class(PHA.TEST.Command).TestWhileGOTO2()
外部ループ
アウター・ループ反復1
内部ループ反復1
外側ループの反復1へ戻る
内部ループの繰り返し2
外側ループの反復1へ戻る
内部ループの繰り返し3
外側ループの反復1へ戻る
内部ループ完了
外部ループ
アウター・ループ反復2
内部ループ完了
外部ループ
アウター・ループ反復3
内部ループ完了
外部ループ
アウター・ループ反復4
内部ループ完了
外部ループ
アウター・ループ反復5
内部ループ完了
すべて完了
/// d ##class(PHA.TEST.Command).TestWhileGOTO3()
ClassMethod TestWhileGOTO3()
{
mainloop ; 外側の入れ子ブロックから内側の入れ子ブロックへ
SET x=1,y=1
WHILE x<6 {
WRITE !,"外部ループ",!
SET x=x+1
WRITE "外側ループの繰り返し ",x-1,!
WRITE "ジャンプ "
GOTO label1
WRITE "これは、",!
WHILE y<4 {
WRITE !," 内部ループの繰り返し ",y,!
SET y=y+1
label1
WRITE "内部ループ ",!
}
WRITE "内部ループ完了",!
}
WRITE "すべて完了"
}
DHC-APP>d ##class(PHA.TEST.Command).TestWhileGOTO3()
外部ループ
アウター・ループ反復1
ジャンプ 内部ループ
内部ループ反復1
内部ループ
内部ループの繰り返し2
内部ループ
内部ループの繰り返し3
内部ループ
内部ループ完了
外部ループ
アウター・ループ反復2
ジャンプ 内部ループ
内部ループ完了
外部ループ
アウター・ループ反復3
ジャンプ 内部ループ
内部ループ完了
外部ループ
アウター・ループ反復4
ジャンプ 内部ループ
内部ループ完了
外部ループ
アウター・ループ反復5
ジャンプ 内部ループ
内部ループ完了
すべて完了
以下の形式のGOTOは実行できますが、GOTOが入力されたブロックの条件テストが失敗するため、「不正」と見なされます:
/// d ##class(PHA.TEST.Command).TestWhileIllegal()
ClassMethod TestWhileIllegal()
{
mainloop ; ブロックに移動する
SET x=1
WRITE "ジャンプ "
GOTO label1
WHILE x>1,x<6 {
WRITE "WHILEループの先頭 x=",x,!
label1
WRITE "WHILEループの最後 x=",x,!!
SET x=x+1
}
}
DHC-APP>d ##class(PHA.TEST.Command).TestWhileIllegal()
WHILEループの一番下にジャンプする x=1
WHILEループの先頭 x=2
WHILEループの最後 x=2
WHILEループの先頭 x=3
WHILEループの最後 x=3
WHILEループの先頭 x=4
WHILEループの最後 x=4
WHILEループの先頭 x=5
WHILEループの最後 x=5
/// d ##class(PHA.TEST.Command).TestWhileIllegal1()
ClassMethod TestWhileIllegal1()
{
mainloop ; コード・ブロックからIF句のブロックへのGOTO。
SET x=1
WHILE x<6 {
WRITE !,"WHILEループ反復=",x,!
SET x=x+1
GOTO label1
WRITE "これは、",!
IF x#2 {
WRITE "IF句",!
label1
WRITE "GOTOIF句を入力する ",!
WRITE x," は奇数である",!
} ELSE {
WRITE "ELSE句の",!
WRITE x," は偶数である",!
}
WRITE "WHILEループの最後",!
}
WRITE "すべて完了"
}
DHC-APP>d ##class(PHA.TEST.Command).TestWhileIllegal1()
WHILEループ反復=1
GOTOIF句に入る
2 が奇数である
WHILEループの最下部
WHILEループ反復=2
GOTOIF句に入る
3 が奇数である
WHILEループの最下部
WHILEループ反復=3
GOTOIF句に入る
4 が奇数である
WHILEループの最下部
WHILEループ反復=4
GOTOIF句に入る
5 が奇数である
WHILEループの最下部
WHILEループ反復=5
GOTOIF句に入る
6 が奇数である
WHILEループの最下部
すべて完了




