第五章 疯狂Caché 运算符和表达式(一)

第五章 Caché 运算符和表达式(一)

Caché支持许多不同的运算符,这些运算符执行各种操作,包括数学操作、逻辑比较等。运算符作用于表达式,表达式是最终计算为某个值的变量或其他实体。

运算符和表达式简介

运算符是指定要对其关联操作数执行的操作的符号字符。每个操作数由一个或多个表达式或表达式原子组成。一起使用时,运算符及其关联的操作数具有以下形式:

[操作数]运算符操作数

有些运算符只接受一个操作数,称为一元运算符;另一些运算符只接受两个操作数,称为二元运算符。

运算符及其任何操作数加在一起构成表达式。这样的表达式产生的结果是运算符对操作数的影响。它们根据它们包含的运算符的类型进行分类。

  • 算术表达式包含算术运算符,对操作数进行数值解释,并生成数值结果。
  • 字符串表达式包含字符串运算符,为操作数提供字符串解释,并生成字符串结果。
  • 逻辑表达式包含关系运算符和逻辑运算符,对操作数进行逻辑解释,并生成布尔结果:TRUE(1)FALSE(0)

运算符符号表

ObjectScript包括以下运算符:

操作符 执行的操作
. 对象属性或方法访问。
() 数组索引或函数调用参数。
+ 加法(二进制)、正(一元)
减法(二进制)、负数(一元)
* 乘法
/ 出发
\ 整除
** 指数
# 余数
_ 连接符
' 逻辑补码(NOT)
= 测试相等性、赋值
'= 不相等
> 大于
'><= 不大于(小于或等于)
< 小于
'<>= 不小于(大于或等于)
[ 包含
] 遵循
]] 排序后
&&& 逻辑AND(&&是AND)
! ,` ` 逻辑或(` `是或)
@ 间接
? 模式匹配

运算符优先

ObjectScript中的运算符优先级严格从左到右;在表达式中,操作按出现的顺序执行。这与其他语言不同,在其他语言中,某些运算符具有比其他运算符更高的优先级。可以在表达式中使用显式括号,以强制某些操作先于其他操作进行。

 WRITE "1 + 2 * 3 = ", 1 + 2 * 3,!  // returns 9
 WRITE "2 * 3 + 1 = ", 2 * 3 + 1,!  // returns 7
 WRITE "1 + (2 * 3) = ", 1 + (2 * 3),!  // returns 7
 WRITE "2 * (3 + 1) = ", 2 * (3 + 1),!  // returns 8
1 + 2 * 3 = 9
2 * 3 + 1 = 7
1 + (2 * 3) = 7
2 * (3 + 1) = 8

一元负运算符

CachéObjectScript使一元负运算符优先于二元算术运算符。CachéObjectScript首先扫描数字表达式并执行任何一元负操作。然后,CachéObjectScript对表达式求值并生成结果。

  WRITE -123 - 3,!       // returns -126
  WRITE -123 + -3,!      // returns -126
  WRITE -(123 - 3),!     // returns -120
-126
-126
-120

括号和优先顺序

可以通过使用匹配的圆括号将表达式相互嵌套来更改计算顺序。圆括号将包含的表达式(算术表达式和关系表达式)分组,并控制CachéObjectScript对表达式执行操作的顺序。

  SET TorF = ((4 + 7) > (6 + 6)) // False (0)
  WRITE TorF
0

这里,由于括号的原因,添加了4和7,就像6和6一样;这导致逻辑表达式11>12,这是假的。请将其与以下内容进行比较:

  SET Value = (4 + 7 > 6 + 6) // 7
  WRITE Value
7

在本例中,优先级从左到右,因此添加了4和7。它们的总和11与6相比较;因为11大于6,所以此逻辑运算的结果是1(True)。然后将1与6相加,结果是7。

请注意,优先级甚至决定了结果类型,因为第一个表达式的最终运算结果是布尔值,而第二个表达式的最后运算结果是数值。

下面的示例显示了多个级别的嵌套:

 WRITE 1+2*3-4*5,!  // returns 25
 WRITE 1+(2*3)-4*5,!  // returns 15
 WRITE 1+(2*(3-4))*5,!  // returns -5
 WRITE 1+(((2*3)-4)*5),!  // returns 11
25
15
-5
11

从最里面的嵌套表达式开始,逐级向前,在每个级别从左到右求值

提示:对于除最简单的ObjectScript表达式之外的所有表达式,最好使用完全括号括起表达式。这是为了消除对顺序的任何模棱两可的地方,也是为了消除将来对代码初衷的任何疑问。

例如,由于“&&”运算符与所有运算符一样具有从左到右的优先顺序,因此下面代码片段中的最后一条语句的计算结果为0:

 SET x = 3
 SET y = 2
 IF x && y = 2 {
   WRITE "True",! } 
 ELSE {
   WRITE "False",! }

False

这是因为按如下方式进行:

  1. 第一个操作是检查x是否已定义并且是否具有非零值。由于x等于3,因此评估将继续。
  2. 接下来,检查y是否已定义并且是否具有非零值。由于y等于2,因此评估将继续。
  3. 接下来,计算3&2的值。由于3和2都不等于0,因此此表达式为真,计算结果为1。
  4. 下一个操作是将返回值与2进行比较。由于1不等于2,因此此计算返回0。

对于那些习惯了许多编程语言的人来说,这是一个意想不到的结果。如果意图是返回True(如果x定义为非零值,并且y等于2),则需要使用括号:

 SET x = 3
 SET y = 2
 IF x && (y = 2) {
   WRITE "True",! } 
 ELSE {
   WRITE "False",! }
True

函数和优先级

某些类型的表达式(如函数)可能会有副作用。假设有以下逻辑表达式:

 IF var1 = ($$ONE + (var2 * 5)) {
    DO ^Test 
 }

CachéObjectScript首先计算var1,然后计算函数$$one,然后计算var2。然后它将var2乘以5。最后,CachéObjectScript测试加法结果是否等于var1中的值如果是,它将执行do命令来调用Test例程

作为另一个示例,请考虑以下逻辑表达式:

  SET var8=25,var7=23
  IF var8 = 25 * (var7 < 24) {
    WRITE !,"True" }
  ELSE {
    WRITE !,"False" }

True

Caché严格从左到右对表达式求值。程序员必须使用括号来建立任何优先级。在本例中,Caché首先计算var8=25,结果为1。然后将此1乘以括号中表达式的结果。因为var7小于24,所以括号中的表达式的计算结果为1。因此Caché与1*1相乘,结果为1(真)。

表达式

ObjectScript表达式是一个或多个“tokens”,可以对其求值以产生值。最简单的表达式只是一个文字或变量:

 SET expr = 22
 SET expr = "hello"
 SET expr = x

可以使用数组、运算符或众多ObjectScript函数之一创建更复杂的表达式:

 SET expr = +x
 SET expr = x + 22
 SET expr = array(1)
 SET expr = ^data("x",1)
 SET expr = $Length(x)
```java
表达式可以由或包括对象属性、实例方法调用或类方法调用组成:
```java
 SET expr = person.Name
 SET expr = obj.Add(1,2)
 SET expr = ##class(MyApp.MyClass).Method()

通过将$$放在例程调用之前,可以直接调用表达式中的ObjectScript例程调用:

 SET expr = $$MyFunc^MyRoutine(1)

表达式可以根据它们返回的值的类型进行分类:

  • 算术表达式包含算术运算符,对操作数进行数值解释,并生成数值结果:
 SET expr = 1 + 2
 SET expr = +x
 SET expr = a + b

请注意,算术表达式中使用的字符串被计算为数字值(如果它不是有效的数字值,则计算为0)。还要注意,使用一元加法运算符(+)将隐式地将字符串值转换为数字值。

  • 字符串表达式包含字符串运算符,为操作数提供字符串解释,并生成字符串结果。
 SET expr = "hello"
 SET expr = "hello" _ x
  • 逻辑表达式包含关系运算符和逻辑运算符,对操作数进行逻辑解释,并生成布尔结果:TRUE(1)FALSE(0)
 SET expr = 1 && 0
 SET expr = a && b
 SET expr = a > b
  • 因此,对象表达式会生成对象引用:
 SET expr = object
 SET expr = employee.Company
 SET expr = ##class(Person).%New()

逻辑表达式

逻辑表达式使用逻辑运算符、数字关系运算符和字符串关系运算符。它们计算表达式并产生布尔值:1(True)0(False)。逻辑表达式最常用于:

  • if命令
  • $select函数
  • 后置条件表达式
    在布尔测试中,任何计算结果为非零数值的表达式都返回布尔值1(True)。任何计算结果为零数值的表达式都返回布尔值0(FALSE)。Caché将非数字字符串计算为具有零数值。

可以使用逻辑运算符组合多个布尔逻辑表达式。与所有Caché表达式一样,它们严格按照从左到右的顺序进行计算。这里有两种类型的逻辑运算符:常规逻辑运算符(&)。和短路逻辑运算符(&&||)。

当使用正则逻辑运算符组合逻辑表达式时,Caché会计算所有指定的表达式,即使布尔结果在所有表达式求值之前已知。这确保了所有表达式都是有效的。

当使用短路逻辑运算符组合逻辑表达式时,Caché只计算确定布尔结果所需的表达式。例如,如果有多个AND测试,则返回0的第一个表达式确定总体布尔结果。不计算此表达式右侧的任何逻辑表达式。可以避免不必要的表达式计算耗时。

某些命令允许将逗号分隔的列表指定为参数值。在本例中,Caché将每个列出的参数作为独立的命令语句进行处理。因此,如果x=7y=4z=2被解析为x=7,那么如果y=4,则如果z=2,这在功能上与短路逻辑运算符语句IF(x=7)&&(y=4)&&(z=2)相同。

在下面的示例中,IF测试使用常规逻辑运算符(&)。因此,即使第一个函数返回0(FALSE),这会自动使整个表达式的结果为FALSE,也会执行所有函数:

LogExp
 IF $$One() & $$Two() {
    WRITE !,"Expression is TRUE."  } 
 ELSE {
    WRITE !,"Expression is FALSE." }
One() 
 WRITE !,"one"
 QUIT 0
Two()
 WRITE !,"two"
 QUIT 1
one
two
Expression is FALSE.

在下面的示例中,IF测试使用短路逻辑运算符(&&)。因此,执行第一个函数并返回0(False),这会自动使整个表达式的结果为false。不执行第二个函数:短路逻辑运算符(&&)

LogExp
 IF $$One() && $$Two() {
    WRITE !,"Expression is TRUE."  } 
 ELSE {
    WRITE !,"Expression is FALSE." }
One() 
 WRITE !,"one"
 QUIT 0
Two()
 WRITE !,"two"
 QUIT 1
one
Expression is FALSE.

在下面的示例中,if测试指定逗号分隔的参数。逗号不是逻辑运算符,但与指定短路&&逻辑运算符的效果相同。执行第一个函数并返回0(False),这会自动使整个表达式的结果为false。不执行第二个函数:

LogExp
 IF $$One(),$$Two() {
    WRITE !,"Expression is TRUE."  } 
 ELSE {
    WRITE !,"Expression is FALSE." }
One() 
 WRITE !,"one"
 QUIT 0
Two()
 WRITE !,"two"
 QUIT 1
one
Expression is FALSE.
/// w ##class(PHA.TEST.ObjectScript).TestComma()
ClassMethod TestComma()
{
    s firstName = "Yao"
    s lastNmae = "Xin"
    i firstName = "Yao",lastNmae = "Xin" d
    .w "true",!
    e  d
    .w "false",!
    
    i firstName = "Yao",lastNmae = "X" d
    .w "true",!
    e  d
    .w "false",!
    
    i firstName = "Y",lastNmae = "Xin" d
    .w "true",!
    e  d
    .w "false",!
    
    i firstName = "Y",lastNmae = "X" d
    .w "true",!
    e  d
    .w "false",!
    q ""
}
DHC-APP>w ##class(PHA.TEST.ObjectScript).TestComma()
true
false
false
false

赋值

在ObjectScript中,set命令与赋值运算符(=)一起使用,为变量赋值。赋值命令的右侧是一个表达式:

 SET value = 0
 SET value = a + b

在ObjectScript中,还可以使用赋值命令左侧的某些函数:

 SET pies = "apple,banana,cherry"
 WRITE "Before: ",pies,!

 // set the 3rd comma-delimited piece of pies to coconut
 SET $Piece(pies,",",3) = "coconut"
 WRITE "After: ",pies
Before: apple,banana,cherry
After: apple,banana,coconut

字符串到数字的转换

字符串可以是数字、部分数字或非数字。

  • 数字字符串完全由数字字符组成。例如,"123", "+123", ".123", "++0007", "-0".
  • 部分数字字符串是以数字符号开头,后跟非数字字符的字符串。例如,"3 blind mice", "-12 degrees".
  • 非数字字符串以非数字字符开头。例如 "123", "the 3 blind mice", "three blind mice".

数字字符串

在算术表达式中使用数字字符串或部分数字字符串时,它将被解释为数字。此数值是通过从左向右扫描字符串以查找可解释为数字文字的最长前导字符序列来获得的。允许使用以下字符:

  • 数字0到9。
  • PlusSign和MinusSign属性值。默认情况下,这些是“+”和“-”字符,但取决于区域设置。使用%SYS.NLS.Format.GetFormatItem()方法返回当前设置。
  • DecimalSeparator属性值。默认情况下,这是“”。字符,但取决于区域设置。使用%SYS.NLS.Format.GetFormatItem()方法返回当前设置。
  • 字母“e”和“E”在表示科学记数法的序列(例如4E3)中时可以作为数字字符串的一部分包括在内。

请注意,NumericGroupSeparator属性值(默认情况下为“,”字符)不被视为数字字符。因此,字符串“123,456”是解析为数字“123”的部分数字字符串。

数字字符串和部分数字字符串在算术运算(如加法和减法)和大于/小于比较运算(<、>、<=、>=)之前转换为规范形式。在相等比较(=,‘=)之前,不会将数字字符串转换为规范形式,因为这些运算符还用于字符串比较操作(<,>,<=,>=)和大于/小于比较操作(<,>,<=,>=)

以下示例显示数字字符串的算术比较:+,<=,>=

  WRITE "3" + 4,!             // returns 7
  WRITE "003.0" + 4,!         // returns 7
  WRITE "++--3" + 4,!         // returns 7
  WRITE "3 blind mice" + 4,!  // returns 7
7
7
7
7

以下示例显示数字字符串的小于(<)比较:

  WRITE "3" < 4,!             // returns 1
  WRITE "003.0" < 4,!         // returns 1
  WRITE "++--3" < 4,!         // returns 1
  WRITE "3 blind mice" < 4,!  // returns 1
1
1
1
1

以下示例显示<=数字字符串的比较:

  WRITE "4" <= 4,!             // returns 1
  WRITE "004.0" <= 4,!         // returns 1
  WRITE "++--4" <= 4,!         // returns 1
  WRITE "4 horsemen" <= 4,!    // returns 1
1
1
1
1

下面的示例显示数字字符串的相等比较。将非规范数字字符串作为字符串进行比较,而不是将其作为数字进行比较。请注意,-0是一个非规范的数字字符串,因此将其作为字符串进行比较,而不是将其作为数字进行比较

  WRITE "4" = 4.00,!          // returns 1
  WRITE "004.0" = 4,!         // returns 0
  WRITE "++--4" = 4,!         // returns 0
  WRITE "4 horsemen" = 4,!    // returns 0
  WRITE "-4" = -4,!           // returns 1
  WRITE "0" = 0,!             // returns 1
  WRITE "-0" = 0,!            // returns 0
  WRITE "-0" = -0,!           // returns 0
1
0
0
0
1
1
0
0

非数字字符串

如果字符串的前导字符不是数字字符,则对于所有算术运算,字符串的数值均为0。对于<、>、‘>、<=、’<和>=比较,非数字字符串也被视为数字0。因为等号同时用于数字等式运算符和字符串比较运算符,所以字符串比较优先用于=‘=运算。可以追加PlusSign属性值(默认情况下为+),以强制对字符串进行数字计算。当x和y是不同的非数字字符串(例如,x=“Fred”,y=“Wilma”)时,这会产生以下逻辑值。

x=y is FALSE x=x is TRUE +x=y is FALSE +x=+y is TRUE +x=+x is TRUE
x'=y is TRUE x'=x is FALSE +x'=y is TRUE +x'=+y is FALSE +x'=+x is FALSE
x < y is FALSE x < x is FALSE +x < y is FALSE +x<+y is FALSE +x<+x is FALSE
x <= y is TRUE x <=x is TRUE +x <=y is TRUE +x<=+y is TRUE +x<=+x is TRUE
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,383评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,522评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,852评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,621评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,741评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,929评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,076评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,803评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,265评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,582评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,716评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,395评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,039评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,027评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,488评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,612评论 2 350