飞道的博客

第七章 疯狂Caché 命令(二)

354人阅读  评论(0)

第七章 疯狂Caché 命令(二)

流程控制命令

为了建立任何代码的逻辑,必须有流控制;有条件地执行或绕过代码块,或重复执行代码块。为此,ObjectScript支持以下命令:

  • IF, ELSEIF, ELSE
  • FOR
  • WHILEDO WHILE

有条件执行

要基于布尔(TRUE/FALSE)测试有条件地执行代码块,可以使用if命令。(可以使用后置条件表达式执行单个CachéObjectScript命令的条件执行。)

IF将表达式作为参数,并计算该表达式为TRUE或FALSE。如果为true,则执行表达式后面的代码块;如果为false,则不执行该代码块。最常见的情况是用推荐值1和0表示这些值。但是,Caché对任意值执行条件执行,如果其计算结果为0(零),则将其计算为false,如果计算结果为非零值,则计算为True。

可以将多个IF布尔测试表达式指定为逗号分隔的列表。这些测试按照从左到右的顺序作为一系列逻辑与测试进行评估。因此,当IF的所有测试表达式都计算为TRUE时,IF的计算结果为TRUE。当IF的其中一个测试表达式的计算结果为False时,IF的计算结果为False;不计算其余的测试表达式。

代码通常出现在包含多个命令的代码块中。代码块只是花括号中包含的一行或多行代码;代码块之前和代码块内可以有换行符。包含多个命令的块。

IF, ELSEIF, ELSE

IF结构允许计算多个条件,并指定根据这些条件运行哪些代码。与简单命令相反,构造由一个或多个命令关键字、它们的条件表达式和代码块组成。IF结构由以下部分组成:

  • 一个带有一个或多个条件表达式的if子句。
  • 任意数量的ELSEIF子句,每个子句都有一个或多个条件表达式。ELSEIF子句是可选的;可以有多个ELSEIF子句。
  • 最多只有一个ELSE子句,没有条件表达式。ELSE子句是可选的。

以下是IF构造的示例:

/// d ##class(PHA.TEST.ObjectScript).TestIf()
ClassMethod TestIf()
{
	READ "Enter the number of equal-length sides in the polygon: ",x
	IF x=1 {WRITE !,"It's so far away that it looks like a point"} 
	ELSEIF x=2 {WRITE !,"I think that's a line, not a polygon"}
	ELSEIF x=3 {WRITE !,"It's an equalateral triangle"}
	ELSEIF x=4 {WRITE !,"It's a square"}
	ELSE {WRITE !,"It's a polygon with ",x," number of sides" }
	WRITE !,"Finished the IF test"
}
DHC-APP>d ##class(PHA.TEST.ObjectScript).TestIf()
Enter the number of equal-length sides in the polygon: 1
It's so far away that it looks like a point
Finished the IF test

FOR

可以使用for构造来重复代码段。可以基于数值或字符串值创建for循环。

通常,For根据数值控制变量的值执行代码块零次或多次,该数值控制变量在代码中的每个循环开始时递增或递减。当控制变量达到其结束值时,控制将退出for循环;如果没有结束值,则循环将一直执行,直到遇到QUIT命令。当控制退出循环时,控制变量将保持其上次执行的循环的值。

数字for循环的形式为:

 FOR ControlVariable = StartValue:IncrementAmount:EndValue {
         // code block content
 }

所有值都可以是正值或负值;等号和冒号周围允许有空格,但不是必需的。对于分配给变量的每个值,将重复FOR后面的代码块。

例如,以下for循环将执行五次:

 WRITE "The first five multiples of 3 are:",!
 FOR multiple = 3:3:15 {
    WRITE multiple,!
 }
The first five multiples of 3 are:
3
6
9
12
15

还可以使用变量来确定终结值。在下面的示例中,变量指定循环的迭代次数:

/// d ##class(PHA.TEST.ObjectScript).TestFor()
ClassMethod TestFor()
{
	SET howmany = 4
	WRITE "The first ",howmany," multiples of 3 are "
	FOR multiple = 1:1:howmany {
		WRITE (multiple*3),", "
			IF multiple = (howmany - 1) {
			WRITE "and "
		}
		IF multiple = howmany {
			WRITE "and that's it!"
		}
	}
	QUIT
}

DHC-APP>d ##class(PHA.TEST.ObjectScript).TestFor()
The first 4 multiples of 3 are 3, 6, 9, and 12, and that's it!

由于此示例使用控制变量Multiple来确定3的倍数,因此它显示表达式Multiple*3。它还使用if命令在最后一个倍数之前插入“and”

注意:本例中的if命令提供了一个很好的示例,说明了ObjectScript中优先顺序的含义(优先顺序总是从左到右,运算符之间没有层次结构)。如果if表达式简单地为“Multiple=howany-1”,没有任何圆括号或圆括号作为一个整体,那么表达式的第一部分“Multiple=howany”将被求值为false(0);然后表达式作为一个整体将等于“0-1”,即-1,这意味着表达式将被求值为true(除了循环中的最后一次迭代之外,对于每种情况都插入“and”)。

for的参数也可以是设置为值列表的变量;在这种情况下,代码块将对分配给该变量的列表中的每一项重复。

/// d ##class(PHA.TEST.ObjectScript).TestChoice()
ClassMethod TestChoice()
{
	FOR b = "John", "Paul", "George", "Ringo" {
		WRITE !, "Was ", b, " the leader? "
		READ choice
	}
}
DHC-APP>d ##class(PHA.TEST.ObjectScript).TestChoice()
 
Was John the leader? John
Was Paul the leader? Ringo
Was George the leader? 1
Was Ringo the leader? 2

通过在特定情况下触发的代码块中放置一个QUIT,可以指定不带结束值的FORE的数字形式,从而终止FOR。此方法提供了已发生的迭代次数的计数器,并允许使用不基于计数器的值的条件来控制。例如,下面的循环使用其计数器通知用户进行了多少次测试:

/// d ##class(PHA.TEST.ObjectScript).TestForBlock()
ClassMethod TestForBlock()
{
	FOR i = 1:1 {
		READ !, "Capital of MA? ", a
		IF a = "Boston" {
			WRITE "...did it in ", i, " tries"
			QUIT
		}
	}
}
DHC-APP>d ##class(PHA.TEST.ObjectScript).TestForBlock()
 
Capital of MA? a
Capital of MA? a
Capital of MA? Boston...did it in 3 tries

如果不需要计数器,则可以使用无参数:使用其计数器通知用户进行了多少次测试:

/// d ##class(PHA.TEST.ObjectScript).TestDeadFor()
ClassMethod TestDeadFor()
{
	FOR  {
		READ !, "Know what? ", wh
		QUIT:(wh = "No!")
		WRITE "   That's what!"
	}
}
DHC-APP>d ##class(PHA.TEST.ObjectScript).TestDeadFor()
 
Know what? 1   That's what!
Know what? 2   That's what!
Know what? 3   That's what!
Know what? 4   That's what!
Know what? 5   That's what!
Know what? No!

WHILEDO WHILE

两个相关的流控制命令是WHILE和DO WHILE命令,每个命令循环遍历代码块并根据条件终止。这两个命令在评估条件时有所不同:While评估整个代码块之前的条件,do While评估块之后的条件。与for一样,代码块内的QUIT将终止循环。

这两个命令的语法为:

 DO {code} WHILE condition
 WHILE condition {code}

下面的示例将斐波纳契序列中的值显示两次,直到用户指定的值-第一次使用DO WHILE,然后使用WHILE

fibonacci() PUBLIC { // generate Fibonacci sequences 
    READ !, "Generate Fibonacci sequence up to where? ", upto
    SET t1 = 1, t2 = 1, fib = 1
    WRITE !
    DO {
        WRITE fib,"  "  set fib = t1 + t2, t1 = t2, t2 = fib
    }
    WHILE ( fib '> upto )

    SET t1 = 1, t2 = 1, fib = 1
    WRITE !
    WHILE ( fib '> upto ) {
        WRITE fib,"  " 
        SET fib = t1 + t2, t1 = t2, t2 = fib
    }
 }

WhileDo WhileFor之间的区别在于, While必须在执行循环之前测试控制表达式的值,但Do While必须在执行循环之后测试值,而For可以在循环内的任何位置测试它。这意味着,如果代码块有两个部分,其中第二个部分的执行取决于表达式的求值,则for构造最合适;否则,选择取决于表达式求值应该在代码块之前还是之后。

I/O 命令

ObjectScript输入/输出命令提供了将数据传入和传出 Caché的基本功能。

Write 命令

CachéObjectScript支持四个命令将文字和变量值写入(显示)到当前输出设备:

  • WRITE 命令
  • ZWRITE 命令
  • ZZDUMP 命令
  • ZZWRITE 命令

无参数显示命令

  • 无参数WRITE显示每个定义的局部变量的名称和值,每行一个变量。它列出了公有变量和私有变量。它列出了公有变量和私有变量。它不列出全局变量、进程私有全局变量或特殊变量。它按排序顺序列出变量。它以下标树顺序列出下标变量。

它将所有数据值显示为由双引号字符分隔的引号字符串,规范数字和对象引用除外。它将分配了对象引用(OREF)值的变量显示为Variable=<Object Reference>[OREF]。它将%LIST格式值或位字符串值以其编码形式显示为带引号的字符串。因为这些编码的表单可能包含非打印字符,所以%列表或位串可能显示为空字符串。

Write不显示某些非打印字符;不显示任何占位符或空格来表示这些非打印字符。WRITE执行控制字符(如换行符或退格符)。

  • 无参数 ZWRITE在功能上与无参数WRITE相同。
  • 无参数 ZZDUMP是生成<语法>错误的无效命令。
  • 无参数 ZZWRITE是返回空字符串的无操作。

显示带有参数的命令

下表列出了这四个命令的参数形式的功能。所有四个命令都可以采用单个参数或逗号分隔的参数列表。所有四个命令都可以将局部、全局或进程私有变量、文字、表达式或特殊变量作为参数:

下表还列出了%Library.Utility.FormatString()方法的默认返回值。FormatString()方法与ZZWRITE最相似,不同之处在于它不将%val=作为返回值的一部分列出,并且它只返回对象引用(OREF)标识符。FormatString()允许将变量设置为ZWRITE/ZZWRITE格式的返回值。

描述 WRITE ZWRITE ZZDUMP ZZWRITE FormatString()
每个值都在单独的行上? NO YES YES (每行16个字符) YES 只有一个输入值
确定的变量名称? NO YES NO %val=表示 NO
未定义的变量导致<UNDEFINED>错误? YES NO(已跳过,未返回变量名) YES YES YES

所有四个命令都计算表达式并以规范形式返回数字。

描述|WRITE ZWRITE ZZDUMP ZZWRITE FormatString()
十六进制表示法? NO NO YES NO
带引号的字符串以区别于数字? NO YES NO YES (字符串文字返回为%val=“value”)
显示的下标节点? NO YES NO NO
显示另一个命名空间(扩展的全局引用)中的全局变量? YES YES (显示的扩展全局引用语法) YES YES
显示非打印字符? NO, 未显示;已执行控制字符 YES, 显示为$c(N) YES,显示为十六进制 YES, 显示为$c(N)
列表值格式 编码字符串 $lb(Val)格式 编码字符串 $lb(Val)格式
%Status 格式 包含编码列表的字符串 包含$lb(Val)格式列表的字符串,附加/*...*/COMMENT指定错误和消息。 包含编码列表的字符串 包含$lb(Val)格式列表的字符串,附加/*...*/COMMENT指定错误和消息。
位串格式 编码字符串 z w c / zwc格式,附加`/* bit()/注释清单1位。例如:%val= z w c ( 407 2 1 2 3 5 ) / zwc(407,2,1,2,3,5)``/* bit(2…4,6)/` 编码字符串 z w c / zwc格式,附加`/* bit()/注释清单1位。例如:%val= z w c ( 407 2 1 2 3 5 ) / zwc(407,2,1,2,3,5)``/* bit(2…4,6)/`
对象引用(OREF)格式 OREF``|<对象引用>[OREF]格式的OREF。列出的一般信息、属性值等详细信息。列出的所有子节点 仅OREF <对象引用>[OREF]格式的OREF。列出的一般信息、属性值等详细信息。 仅OREF,带引号的字符串

所有这些命令都将JSON动态数组和JSON动态对象作为OREF值返回。要返回JSON内容,必须使用%ToJSON(),如下例所示:

/// d ##class(PHA.TEST.ObjectScript).TestWhiteJson()
ClassMethod TestWhiteJson()
{
	SET jobj={"name":"Fred","city":"Bedrock"}
	w jobj.%ToJSON(),!
	WRITE "JSON object reference:",!
	ZWRITE jobj
	WRITE !!,"JSON object value:",!
	ZWRITE jobj.%ToJSON()
	w "",!
	ZZWRITE jobj.%ToJSON()
}
DHC-APP>d ##class(PHA.TEST.ObjectScript).TestWhiteJson()
{"name":"Fred","city":"Bedrock"}
JSON object reference:
jobj=<OBJECT REFERENCE>[1@%Library.DynamicObject]
+----------------- general information ---------------
|      oref value: 1
|      class name: %Library.DynamicObject
| reference count: 2
+----------------- attribute values ------------------
|           (none)
+-----------------------------------------------------
 
 
JSON object value:
"{""name"":""Fred"",""city"":""Bedrock""}"
 
%val="{""name"":""Fred"",""city"":""Bedrock""}"

READ

读取命令允许接受并存储最终用户通过当前输入设备输入的输入。READ命令可以具有以下任何参数:

  READ format, string, variable

其中Format控制用户输入区域在屏幕上的显示位置,字符串将出现在输入提示之前,Variable将存储输入数据。

以下格式代码用于控制用户输入区域:

格式代码 效果
! 新起一行。
# 新起一页。在终端上,它清除当前屏幕并从新屏幕的顶部开始。

?n| 位于第n列位置的位置,其中n是正整数。

/// d ##class(PHA.TEST.ObjectScript).TestWhiteAll()
ClassMethod TestWhiteAll()
{
	w "这是,!",!
	w "这是,#",#
	w "这是,?10",?10
	w "这是,?20",?20
	w "这是,?30",?30
}
DHC-APP>d ##class(PHA.TEST.ObjectScript).TestWhiteAll()
这是,!
这是,#
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
这是,?10    这是,?20    这是,?30

OPEN, USE, CLOSE

对于更复杂的设备处理,Caché提供了丰富的选择。简而言之,可以使用OPEN命令获取打开设备的所有权;使用USE命令指定当前设备;使用CLOSE命令关闭打开设备。


转载:https://blog.csdn.net/yaoxin521123/article/details/106169415
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场