文章目錄
第八章 瘋狂Caché 調用自定義代碼模塊(一)
本章介紹如何創建和調用用戶定義的ObjectScript代碼模塊。這些代碼單元可以是用戶定義的函數、過程、方法、例程或子例程。
與在其他語言中一樣,ObjectScript允許創建可以直接調用的命名代碼塊。這樣的塊稱爲過程。嚴格地說,在ObjectScript中,作爲過程的代碼塊具有特定的語法和結構。
過程定義的語法如下:
ProcedureName(Parameters) [PublicVariables]
{
/* code goes here */
QUIT ReturnValue
}
該過程的元素(此處稱爲ProcedureName)包括:
- 參數(零個或更多) 它們可以是任何類型,並且與ObjectScript的典型情況一樣,在定義過程時不需要聲明它們的類型。默認情況下,它們是通過值(而不是通過引用)傳遞的。除非另有說明,否則它們的作用域是過程的局部作用域。
- 對公共變量的引用(零個或更多) 這些也可以是任何類型的。該過程可以引用和設置此類變量的值。
- 聲明該過程是公共的(可選) 默認情況下,過程是私有的,這意味着只能從同一例程的其他位置調用它們(在ObjectScript術語中,例程是包含一個或多個過程Procedures或其他用戶定義的代碼塊的文件)。還可以創建公共的過程,在過程名稱後使用PUBLIC關鍵字。可以從其他例程或方法調用公共過程。
- 代碼 過程中的代碼具有ObjectScript中提供的所有功能。過程代碼還可以包括BASIC和Java。代碼由大括號分隔,也稱爲過程塊。
- 返回值(可選) 這是該過程返回的值,並且必須是標準ObjectScript表達式。過程內的流程控制可以使用計算表達式值和/或多個QUIT語句指定各種返回值。
注意:對於熟悉版本5之前的Caché版本(以及爲這些版本編寫的代碼)的人來說,Procedures過程比以前在子例程和用戶定義函數中提供的編碼更先進。過程參數在過程內的作用域中自動是局部的。它們不需要NEW命令來確保它們不會覆蓋其他值,因爲它們是過程專用的,並且不與符號表交互。此外,公共變量的顯式聲明允許引用應用程序中的全局變量,例如銀行範圍的利率;它還允許爲過程中的變量創建和設置可供應用程序其餘部分使用的值。
Procedures過程是一種特殊的ObjectScript例程。
Caché還提供了大量系統提供的函數,所有這些函數都在ObjectScript語言參考中進行了描述;這些函數有時稱爲內部函數。對系統函數的調用由“$
”前綴標識。
Procedures, Routines, Subroutines, Functions, Methods 他們是什麼?
本章介紹如何使用過程實現自己的代碼,這些過程是實現用戶定義功能的推薦形式。雖然Procedures, Routines, Subroutines, Functions, Methods這些實體都有共同的功能,但每個實體都有自己的特點。最值得注意的是,在Caché5.0版本之前創建的應用程序通常包括未實現爲過程.res的子例程和函數,每個子例程和函數都有自己的特徵。因此,爲實現自己的代碼提供所有這些不同結構的簡要概述是很重要的。
最靈活、最強大、最推薦的命名用戶定義代碼塊形式是過程。程序的特點包括:
- 可以是私有的,也可以是公共的。
- 可以接受零個或多個參數。
- 自動將在其中創建的任何變量維護爲作用域中的局部變量。
- 可以引用和更改它外部的變量。
- 可以返回任何類型的值,也可以不返回值。
重要提示:默認情況下,方法是過程。正因爲如此,本章中關於過程的所有內容也都描述了方法。
相比之下:
- 子例程始終是公共的,不能返回值。
- 函數始終是公共的,需要顯式聲明局部變量(否則將覆蓋外部變量),並且必須具有返回值。
- 默認情況下,方法是作爲類定義的一部分指定的過程,可以在一個或多個對象或類上調用該過程。如果顯式聲明它是一個函數,那麼它就是一個具有所有附帶特徵的函數;不建議這樣做。
- 例程是ObjectScript程序。它可以包括一個或多個過程、子例程和函數,以及三者的任意組合。
ObjectScript還通過其宏工具支持相關形式的用戶定義代碼。
Routines
例程是一個可調用的用戶編寫的代碼塊,它是一個ObjectScript程序。例程執行通常需要的操作。其名稱由選擇用於保存它的.Mac文件的名稱確定。根據例程是否返回值,可以使用以下一組語法或兩組語法調用例程:
DO ^RoutineName
SET x = $$^RoutineName
w 1,"!"
w 2,"!"
s white="白色"
w white,!
DHC-APP>D ^PHA.MOB.TEST
1!2!白色
例程在命名空間內定義。可以使用擴展例程引用來執行在當前命名空間以外的命名空間中定義的用戶定義例程:
DO ^|"SAMPLES"|RoutineName
通常,例程充當子例程、方法和過程的容器。
此標籤(通常)後跟括號,其中包含要從調用程序傳遞到例程的參數列表。
將例程保存到文件時,文件名不能包含下劃線(“_
”)、連字符(“-
”)或分號(“;
”)字符;包含此類字符的名稱無效。
Subroutines
子例程是例程內的命名代碼塊。通常,子例程以LABEL開頭,以QUIT
語句結束,它可以接受參數,不返回值。要調用子例程,請使用以下語法:
DO Subroutine^Routine
其中,子例程是例程文件(Routine.MAC)中的代碼塊。
子例程的形式爲:
Label(parameters) // comment
// code
QUIT // note that QUIT has no arguments
如果將代碼和QUIT
語句用大括號括起來,則該子例程是一個過程,可以這樣處理。
Functions
Caché附帶許多系統提供的函數(有時稱爲“內部intrinsic”函數).本節介紹用戶定義的(“外部extrinsic”)函數。
函數是例程中的命名代碼塊。通常,函數以LABEL開頭,以QUIT
語句結束。它可以接受參數,也可以返回值。要調用函數,有兩種有效的語法形式:
SET rval=$$Function() /* 返回值 */
DO Function^Routine /* 忽略返回值 */
其中函數是例程文件(Routine.MAC)中的代碼塊。在這兩種語法形式中,都可以使用擴展例程引用來執行位於不同名稱空間中的函數。
函數的形式爲:
Label(parameters)
// code
QUIT ReturnValue
如果將代碼和QUIT
語句用大括號括起來,則該函數是一個過程,可以這樣處理。請注意,因爲默認情況下過程是私有的,所以可能希望指定PUBLIC關鍵字,如下所示:
Label(parameters) PUBLIC {
// code
QUIT ReturnValue }
如果方法是私有的你調用的話
Main PRIVATE ;
TRY {
KILL x
SET x=$$MyFunc(7,10)
s y = $$Call
d Start
WRITE "returned value is ",x,!
RETURN
}
CATCH { WRITE $ZERROR,!
}
MyFunc(a,b)
SET c=a+b
QUIT c
/// d ##class(PHA.TEST.ObjectScript).TestRoute()
ClassMethod TestRoute()
{
d Main^PHA.MOB.TEST
}
DHC-APP>d ##class(PHA.TEST.ObjectScript).TestRoute()
d Main^PHA.MOB.TEST }
^
<NOLINE>zTestRoute+1^PHA.TEST.ObjectScript.1
下面的示例定義一個簡單函數(MyFunc)並調用它,傳遞兩個參數並接收返回值:main
;
Main ;
TRY {
KILL x
SET x=$$MyFunc(7,10)
WRITE "returned value is ",x,!
RETURN
}
CATCH { WRITE $ZERROR,!
}
MyFunc(a,b)
SET c=a+b
QUIT c
DHC-APP>D Main^PHA.MOB.TEST
returned value is 17
調用函數的代碼可以忽略返回值,但函數的Quit
命令必須指定返回值。嘗試使用無參數退出退出函數會生成<command>
錯誤。<command>
錯誤指定調用函數的調用位置,後跟一條消息,指定無參數退出命令在被調用函數中的偏移位置。
定義程序
與在其他語言中一樣,過程是完成特定任務的一系列ObjectScript命令(較大例程的一部分)。與IF
等構造類似,過程的代碼包含在大括號中。
過程允許將每個變量定義爲公共變量或私有變量。例如,以下過程稱爲“MyProc
”:
MyProc(x,y) [a,b] PUBLIC {
Write "x + y = ", x + y
}
定義一個名爲“MyProc”的公共過程,該過程接受x
和y
兩個參數。它定義兩個公共變量a
和b
。該過程中使用的所有其他變量(在本例中爲x
和y
)都是私有變量。
默認情況下,過程是私有的,這意味着只能從同一例程中的其他地方調用它們。還可以創建公共的過程,在過程名稱後使用Public
關鍵字。可以從其他例程調用公共過程。
過程不需要定義參數。要創建帶有參數的過程,請將帶括號的變量列表緊跟在標籤之後。
調用程序
要調用過程,要麼發出指定該過程的do
命令,要麼使用“$$
”語法將其作爲函數調用。可以控制是從任何程序(公共)調用過程,還是隻能從其所在的程序(私有)調用過程。如果用DO
調用,過程不返回值;如果作爲函數調用調用,過程返回值。“$$
”表單提供的功能最多,通常是首選表單。
使用$$
前綴
可以在允許表達式的任何上下文中調用用戶定義函數。用戶定義的函數調用採用以下形式:
$$name([param[ ,...]])
- name 指定函數的名稱。根據函數的定義位置,名稱可以指定爲:
- label 是當前例程內的行標籤
- LABEL^ROUTINE是駐留在磁盤上的命名例程中的行標籤。
- ^routine是駐留在磁盤上的例程。例程必須僅包含要執行的函數的代碼。
- param 指定要傳遞給函數的值。提供的參數稱爲實際參數列表。它們必須與爲函數定義的形參列表匹配。例如,函數代碼可能需要兩個參數,第一個是數值,第二個是字符串文字。如果爲第一個參數指定字符串文字,爲第二個參數指定數值,則函數可能會生成不正確的值或可能生成錯誤。形參列表中的參數總是由函數調用
new
。參數可以通過值傳遞,也可以通過引用傳遞。如果傳遞給函數的參數比函數的正式參數列表中列出的參數少,則使用參數默認值(如果已定義);如果沒有默認值,則這些參數保持未定義狀態。
使用DO
命令
可以使用do
命令調用用戶定義的函數。(不能使用do
命令調用系統提供的函數。) 使用DO
調用的函數不返回值。也就是說,函數必須生成返回值,但do
命令會忽略該返回值。這極大地限制了使用DO
調用用戶定義的函數。
要使用DO
調用用戶定義的函數,請使用以下語法發出命令:
DO label(param[,...])
do
命令調用名爲Label的函數,並向其傳遞由param指定的參數。請注意,不使用$$
前綴,參數括號是必需的。 指定標籤和參數的規則與使用$$
前綴調用用戶定義函數時的規則相同。
函數必須始終返回值。但是,當使用DO
調用函數時,調用程序會忽略此返回值。
程序語法
label([param[=default]][,...]) [[pubvar[,...]]] [access] {
code
}
調用語法:
DO label([param[,...]])
和
command $$label([param][,...])
- label 程序名稱。一個標準的標籤。它必須從第一列開始。標籤後面的參數括號是必需的。
- param 程序的每個參數的變量。這些參數稱爲形式參數列表。參數本身是可選的(可能沒有、可能有一個或多個參數),但括號是必需的。多個參數值用逗號分隔。參數可以按值或按引用傳遞到形參列表。作爲例程的過程不包含有關其參數的類型信息;作爲方法的過程包含此信息。形參的最大數量爲255個。
- default 它前面的參數的可選默認值。可以爲每個參數提供或省略默認值。當沒有爲該形參提供實際參數時,或者當通過引用傳遞實際參數並且所討論的局部變量沒有值時,將應用默認值。此默認值必須是文字:可以是數字,也可以是用引號括起來的字符串。可以指定空字符串(
“”
)作爲默認值。這與未指定默認值不同,因爲空字符串定義變量,而未指定或未指定默認值的參數的變量將保持未定義狀態。如果指定的默認值不是文字,則Caché會發出<參數>
錯誤。 - pubvar 公共變量。程序使用並可用於其他例程和程序的公共變量的可選列表。這是一個變量列表,這些變量既在此程序中定義,也可用於其他例程,並在另一個例程中定義,可用於此過程。如果指定,則將pubvar括在方括號中。如果未指定pubvar,則可以省略方括號。多個pubvar值用逗號分隔。所有未聲明爲公共變量的變量都是私有變量。私有變量僅對過程的當前調用可用。它們在調用過程時未定義,在退出過程時銷燬。如果該過程調用該過程外部的任何代碼,則私有變量將被保留,但在調用返回到該過程之前不可用。所有
%
變量始終是公共的,無論它們是否在此處列出。公共變量列表可以包括爲此例程指定的一個或多個參數。 - access 一個可選關鍵字,用於聲明過程是公共的還是私有的。有兩個可用值:
public
,它聲明可以從任何例程調用此過程。Private
,它聲明此過程只能從定義它的例程中調用。私有是默認設置。 - code 一段代碼,用大括號括起來。左花括號(
{
)必須與其前後的字符至少用一個空格或換行符分隔。右大括號(}
)後面不能跟同一行的任何代碼;它後面只能跟空格或註釋。右大括號可以放在第一列。此代碼塊僅通過標籤輸入。
不能在命令及其參數之間插入換行符。
每個程序都作爲例程的一部分實現;每個例程可以包含多個程序。
除了標準的ObjectScript語法之外,還有管理例程的特殊規則。例程中的一行可以在開頭有標籤(也稱爲標記)、ObjectScript代碼和結尾的註釋;但所有這些元素都是可選的。
InterSystems建議例程的第一行有一個與例程名稱匹配的標籤,後跟一個製表符或空格,後跟一個解釋例程目的的簡短註釋。如果行有標籤,則必須用製表符或空格將其與行的其餘部分隔開。這意味着當使用Studio向例程添加行時,可以鍵入標籤和製表符/空格,然後鍵入ObjectScript代碼,或者跳過標籤並鍵入製表符或空格,然後鍵入ObjectScript。因此,在任何一種情況下,每行都必須在第一個命令之前有製表符或空格。
要表示單行註釋,請使用雙斜槓(“//
”)或分號(“;
”)。如果註釋跟在代碼後面,則斜槓或分號之前必須有空格;如果該行只包含註釋,則斜槓或分號之前必須有製表符或空格。根據定義,單行註釋中不能有換行符;對於多行註釋,註釋的開頭用“/*”標記,註釋的結尾用“*/”
標記。
程序變量
程序和方法都支持私有變量和公共變量;以下所有語句都同樣適用於程序和方法:
程序中使用的變量自動成爲該程序的私有變量。因此,不必這樣聲明它們,它們也不需要New
命令。要與此過程調用的過程共享其中一些變量,請將它們作爲參數傳遞給其他過程。
還可以聲明公共變量。它們可用於所有過程和方法;即此過程或方法調用的過程和方法以及調用此過程或方法的過程和方法。應該以這種方式定義數量相對較少的變量,以充當應用程序的環境變量。要定義公共變量,請將它們列在過程名稱及其參數後面的方括號中。
publicvarsexample
DO proc1(4,5)
QUIT
proc1(e,f) [a, b]
{
WRITE !, "setting a" SET a = 10
WRITE !, "setting b" SET b = 20
WRITE !, "setting c" SET c = 30
SET d = a + b + c
w !,d+e+f,!
WRITE !, "The sum is: ", d,!
d proc2(9,9)
}
proc2(g,h)[a, b]{
w a+b,!
}
DHC-APP>d publicvarsexample^PHA.MOB.TEST
setting a
setting b
setting c
69
The sum is: 60
30
公有變量與私有變量
在程序中,局部變量可以是“公共的”或“私有的”。公共列表(Pubvar)聲明程序中的哪些變量引用被添加到公共變量集;程序中的所有其他變量引用都是對只有當前過程調用才能看到的私有集的引用。
私有變量在進入過程時未定義,在退出過程時銷燬。
當過程內的代碼調用該過程外的任何代碼時,私有變量將在返回該過程時恢復。被調用的程序或例程可以訪問公共變量(以及它自己的私有變量)。因此,pubvar既指定了該程序看到的公共變量,也指定了該過程調用的例程能夠看到的該過程中使用的變量。
如果公有變量列表爲空,則所有變量都是私有的。在這種情況下,方括號是可選的。
名稱以“%
”字符開頭的變量通常是系統使用或用於某些特殊目的的變量。所有這樣的%
變量都是隱式公共的。它們可以列在公用名單中,但不是必需的。
私有變量與使用NEW創建的變量
請注意,私有變量與使用new新創建的變量不同。 如果過程要使變量直接供其調用的其他過程或子例程使用,則該變量必須是公共變量,並且必須在公用列表中列出。如果它是此程序引入的公共變量,則對其執行new
是有意義的。這樣,當我們退出過程時,它將自動銷燬,並且它還保護公共變量之前可能具有的任何值。 例如,代碼:
MyProc(x,y)[name]{
NEW name
SET name="John"
DO xyz^abc
QUIT
}
使例程“abc
”中的程序“xyz
”能夠看到名稱的值“john
”,因爲它是公共的。調用name
的new
命令可以保護調用過程“MyProc
”時可能已經存在的名爲“name
”的公共變量。
new
命令不影響私有變量;它只對公共變量起作用。在程序中,如果x
未在公共變量列表中列出並且x
不是%
變量,則指定new x
或new(X)
是非法的。
公開形式列表參數
如果過程具有它調用的其他過程需要的正式列表參數(如MyProc(x,y)
中的“x
”或“y
”),則該參數應列在公用列表中。
MyProc(x,y)[x] {
DO abc^rou
}
使x
的值(而不是y
的值)可用於例程“abc^rou
”。
publicvarsexample
DO proc1(4,5)
QUIT
proc1(e,f) [a, b]
{
WRITE !, "setting a" SET a = 10
WRITE !, "setting b" SET b = 20
WRITE !, "setting c" SET c = 30
SET d = a + b + c
w !,d+e+f,!
WRITE !, "The sum is: ", d,!
d proc2(9,9)
}
proc2(g,h)[a, b]{
w a+b,!
s a=40
s b=50
d proc3
}
proc3
w a+b,!
DHC-APP>d publicvarsexample^PHA.MOB.TEST
setting a
setting b
setting c
69
The sum is: 60
30
90
公共和私有程序
程序可以是“公共的”或“私有的”。私有程序只能從定義該過程的例程內調用,而公共程序可以從任何例程調用。如果省略PUBLIC
和PRIVATE
關鍵字,則默認爲“PRIVATE
”。
定義公共程序
MyProc(x,y) PUBLIC { }
而
MyProc(x,y) PRIVATE { }
和
MyProc(x,y) { }
兩者都定義了私有過程。