条件为真时执行代码。
FOR
循环将新级别推入堆栈。 WHILE
循环不会更改堆栈级别。调试FOR
循环时FOR
与WHILE
在单步调试的时候有区别。WHILE expression,... {
code
}
WHILE
测试表达式,如果expression的计算结果为TRUE,则它将执行左花括号和右花括号之间的代码块(一个或多个命令)。只要expression的计算结果为TRUE,WHILE
就可以重复执行一段代码。如果expression不为TRUE,则不执行花括号内的代码块,并执行紧跟大括号(}的下一个命令。
程序员必须小心避免WHILE
无限循环。 WHILE 1
{… …(或任何其他永远不能评估为false的WHILE
表达式)执行无限循环,因此循环代码必须发出QUIT
退出循环。
左花括号或右花括号可以出现在其自己的代码行中,也可以与命令显示在同一行中。第1列中甚至可能会出现一个打开或关闭的花括号(尽管不建议这样做)。建议的编程做法是缩进大括号以指示嵌套代码块的开始和结束。在花括号前或后不需要空格。在右花括号之前(包括紧随无参命令的花括号),不需要空格。花括号只需要一个空格:右花括号必须与后面的命令用空格,制表符或换行符分隔。
花括号中的代码块可以包含一个或多个ObjectScript命令和函数调用。此代码块可能跨越几行。代码块中允许缩进,换行和空格。此代码块中的命令和命令中的参数可以用一个或多个空格或行返回分隔。
布尔测试条件。它可以采用单个表达式或逗号分隔的表达式列表的形式。如果Caché将表达式计算为TRUE(任何非零数值),则执行WHILE
循环。通常,表达式是条件测试,例如x < 10
或“ apple” =“ apple”
,但是任何计算结果为非零数字的值均为TRUE。例如7、00.1,“ 700”,“ 7dwarves”
全部求值为TRUE。任何值为零的值为FALSE。例如,0,-0和任何非数字字符串都计算为FALSE。
对于表达式列表,Caché以从左到右的顺序计算各个表达式。如果遇到计算结果为0(FALSE)的表达式,它将停止计算。表达式右边的任何表达式的值为FALSE都不会得到验证或测试。
如果所有表达式的计算结果均为非零数值(TRUE),则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
下面的示例对执行两个表达式测试。这两个测试用逗号分隔。如果两个测试的结果都为true,则执行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
来执行相同的操作:循环,直到事件导致执行脱离循环为止。但是,使用哪种循环结构会对在代码模块上执行单步调试(BREAK“ S +”
或BREAK“ L +”
)产生影响。
FOR
循环将新级别推入堆栈。 WHILE
循环不会更改堆栈级别。调试FOR
循环时,从FOR
循环内部弹出堆栈(使用BREAK“ C” GOTO
或QUIT 1
)可让在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()
循环1
循环2
循环3
循环4
循环5
完成
WHILE
代码块可以嵌套。即,一个WHILE
代码块可以包含另一个控制流循环(另一个WHILE
或FOR
或DO 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
终止例程的执行,包括从WHILE
循环或嵌套循环结构中终止。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循环中
GOTO之后仍处于WHILE循环中
x=2
在WHILE循环中
GOTO之后仍处于WHILE循环中
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 "GOTO进入IF子句",!
WRITE x," 是一个奇数",!
} ELSE {
WRITE "在ELSE子句中",!
WRITE x," 是一个偶数",!
}
WRITE "WHILE循环的底部",!
}
WRITE "全部完成"
}
DHC-APP>d ##class(PHA.TEST.Command).TestWhileIllegal1()
WHILE循环迭代=1
GOTO进入IF子句
2 是一个奇数
WHILE循环的底部
WHILE循环迭代=2
GOTO进入IF子句
3 是一个奇数
WHILE循环的底部
WHILE循环迭代=3
GOTO进入IF子句
4 是一个奇数
WHILE循环的底部
WHILE循环迭代=4
GOTO进入IF子句
5 是一个奇数
WHILE循环的底部
WHILE循环迭代=5
GOTO进入IF子句
6 是一个奇数
WHILE循环的底部
全部完成