注釋
在Pascal中,注釋括在大括弧中或帶星號的圓括弧中。Delphi 也認可C++ 風格的注釋,即把注釋放在雙斜線後。例如
{this is a comment}(* this is another comment *)// this is a comment up to the end of the line
第一種注釋方式較簡略,使用也較為普遍;第二種方式在歐洲使用較廣 ,因為歐洲的鍵盤缺少大括弧;第三種方式的注釋是從C++借用來的,只在32位版本的Delphi中可用,它在給一行代碼加短注釋時非常有用。
在這本書中我用斜體表示注釋,用粗體表示關鍵詞,以此與預設的Delphi文法風格表示一致。
上述三種不同的注釋方式有益於進行嵌套注釋。例如你要登出一段代碼,而程式碼中又包含真正的注釋行,這時採用同一種注釋方式是不對的:
{ ... code{comment, creating problems}... code }
正確的方法是插入第二種注釋方式:
{ ... code//this comment is OK... code }
注意:如果左大括弧或圓括弧-星號後面跟貨幣符號($),那麼其中的內容就成了編譯指令,如 {$X+}。
實際上,編譯指令仍是注釋。例如,{$X+ This is a comment} 是合法的。這既是有效編譯指令又是一條注釋,儘管明智的程式員很可能會注意把編譯指令和注釋分開。
使用大寫字母
Pascal 編譯器(不象其他語言的編譯器)不考慮字元的大小寫,因此標識符Myname、 MyName、 myname、 myName、 和MYNAME是完全相同的。總體上來說,這是Pascal的一大優點,因為在大小寫敏感的語言中,許多語法錯誤是由不正確的大寫引起的。
注意:Pascal語言的大小寫不敏感特性有一個例外:控制項包中的Register 過程必須以大寫字母R開始,因為需要與C++Builder 相容。
然而大小寫不敏感也有不便之處:第一,你必須注意大小寫不一致的標識符實際上是相同的,以避免把他們當成不同的元素使用;第二,你必須盡量保持大寫使用的一致性,以提高代碼的可讀性。
大寫使用的一致性不是編譯器強制要求的,但是保持大寫使用的一致性是值得提倡的好習慣。一個常用的方法是將每個標識符的第一個字母大寫,標識符若由幾個片語合而成(中間不能插入空格),每個詞的第一個字母應大寫:
MyLongIdentifierMyVeryLongAndAlmostStupidIdentifier
此外,編譯器不編譯代碼中的空格、空行和Tab鍵空格,這些元素通稱為空白,它們只用來提高代碼的可讀性,不影響編譯過程。
不同於BASIC, Pascal 語句允許分行書寫,即將一條長指令分割成兩個或更多的程式碼。允許語句分行的缺點(至少對許多BASIC程式員)是:語句結束時不能忘了加分號,更確切地說,必須記著把語句和緊接它的語句分開。語句分行唯一的限制是字串不能跨行。
關於空格和語句分行的使用沒有既定的規則,以下是幾點經驗:
- Delphi 代碼編輯器中有一條豎線叫右邊線(Right Margin),你可以把右邊線設定在60或70個字元處。如果以這條線為基準,代碼不超過這條界限,那麼列印到紙上的代碼看起來會很好看。否則,列印時間長度語句會被隨意分行,甚至在一個詞的中間斷開。
- 當一個函數或過程有多個參數,通常的做法是把各參數放在不同的行上。
- 你可以在注釋行前留一行空白,或把長的代碼句分成較小的部分,這樣能提高代碼的可讀性。
- 用空格隔開函數調用的參數,運算式中的運算子也最好用空格隔開。一些程式員可能會對這些提議不以為然,但我堅持認為:空格是免費的,你不必為使用空格付費,何樂而不為呢?
最佳化版面
關於代碼編寫風格的最後一條建議是:盡量使用空白最佳化版面。這一條很容易做到,只需要在寫複合句時,以上一句為參照,下一句向右縮排兩個空格,複合句內嵌的複合句縮排四個空格,依此類推。例如:
if ... then statement;if ... thenbegin statement1; statement2;end;if ... thenbegin if ... then statement1; statement2;end;
相似的縮排格式常用於變數或資料類型聲名區,也可用於語句的續行:
type Letters = set of Char;var Name: string;begin { long comment and long statement, going on in the following line and indented two spaces } MessageDlg ('This is a message', mtInformation, [mbOk], 0);
提出以上代碼編寫格式只是向你建個議而已,這樣代碼能更加易讀,其實代碼格式並不影響編譯結果。在本書的例子和程式碼片段中我始終堅持使用上述代碼風格,Delphi 中的原始碼、手冊和協助例子均採用了相似的格式化風格。
突出Pascal元素
為了使Pascal 代碼更易讀寫,Delphi 編輯器中增加了Pascal 元素的色彩設定功能,也就是編輯器會用不同的顏色表示不同的Pascal 元素。預設情況下,關鍵字以粗體表示,字串和注釋用藍色表示(並且常常是斜體)。
用不同色彩顯示不同的Pascal 元素對保留字、注釋和字串十分有利,因為著色後你一眼就可以看出拼錯的關鍵字、沒有正常結束的字串及多行注釋。
使用編輯器環境選項對話方塊中的色彩(Color)頁,很容易就能定製各種Pascal 元素的色彩(見圖2.1)。如果獨自工作,那麼你可隨意選擇喜歡的顏色。如果是與其他程式員合作,那麼應該使用大家統一的標準顏色。我感覺在同一台電腦上使用我不習慣的色彩配置確實很難受。
圖2.1 編輯環境設定對話方塊
注意:本書中我選用了一種色彩方案來顯示原始碼清單,希望能使代碼更易讀。
使用代碼模板
Delphi 3 中增加了用於代碼編輯的新功能“代碼模板”。由於寫Pascal 語句時,常常會重複鍵入相同的一組關鍵字,為此Borland 公司開發了名為“代碼模板”的新功能,代碼模板中存放了能與代碼縮減形式對應的完整代碼,你輸入縮減代碼,然後按Ctrl+J,完整的代碼就出現了。例如,你輸入arrayd,然後按Ctrl+J,Delphi 編輯器會把你的文本擴充為:
array [0..] of ;
由於同一種代碼結構在預定義的代碼模板中通常有多種樣式,所以模板中的縮減形式一般加有一個尾碼字母,以便你選用。此外,你也可以只輸入縮減形式的頭幾個字母,如你輸ar,然後按Ctrl+J,那麼,編輯器中會彈出一個菜單,菜單中列出了代碼縮減形式選項,見圖2.2所示。
圖2.2 代碼模板選項
代碼模板可以定製,就是你可以修改已有的模板也可以添加自己常用的程式碼片段。用代碼模板輸入的代碼文本中通常會出現‘|’字元,它表示輸入模板代碼後游標應跳到的位置,就是說你應該從這個游標位置開始輸入,寫完這句代碼。
編程語句
標識符一經定義 ,你就可以在語句及組成語句的運算式中使用它們。Pascal 提供了許多語句和運算式,首先來看看關鍵字、運算式和運算子。
關鍵字
關鍵字是Object Pascal 的保留標識符,在語言中有著特殊含義。保留字不能用作標識符,指令字也同樣不應該用作標識符,即使編譯器允許也最好不用。在實際中你不應該把任何關鍵字用作標識符。
表2.1是物件導向 Pascal 語言(Delphi 4)中特殊標識符的完整列表,其中包括關鍵字及保留字。
表2.1:物件導向Pascal語言中的關鍵字及保留字
| 關鍵字 |
作用 |
| absolute |
指令 (變數) |
| abstract |
指令 (方法) |
| and |
運算子 (布爾) |
| array |
類型 |
| as |
運算子 (RTTI) |
| asm |
語句 |
| assembler |
向後相容 (彙編) |
| at |
語句 (異常處理) |
| automated |
訪問類別符 (類) |
| begin |
塊標記 |
| case |
語句 |
| cdecl |
函數調用協定 |
| class |
類型 |
| const |
聲明或指令(參數) |
| constructor |
特殊方法 |
| contains |
運算子 (集合) |
| default |
指令 (屬性) |
| destructor |
特殊方法 |
| dispid |
dispinterface 介面類別符 |
| dispinterface |
類型 |
| div |
運算子 |
| do |
語句 |
| downto |
語句 (for) |
| dynamic |
指令 (方法) |
| else |
語句 (if 或 case) |
| end |
塊標記 |
| except |
語句 (異常處理) |
| export |
向後相容 (類) |
| exports |
聲明 |
| external |
指令 (函數) |
| far |
向後相容 (類) |
| file |
類型 |
| finalization |
單元結構 |
| finally |
語句 (異常處理) |
| for |
語句 |
| forward |
函數指令 |
| function |
聲明 |
| goto |
語句 |
| if |
語句 |
| implementation |
單元結構 |
| implements |
指令 (屬性) |
| in |
運算子 (集合) - 工程結構 |
| index |
指令 (dipinterface介面) |
| inherited |
語句 |
| initialization |
單元結構 |
| inline |
向後相容 (見 asm) |
| interface |
類型 |
| is |
運算子 (RTTI) |
| label |
聲明 |
| library |
程式結構 |
| message |
指令 (方法) |
| mod |
運算子 (數學) |
| name |
指令 (函數) |
| near |
向後相容 (類) |
| nil |
數值 |
| nodefault |
指令 (屬性) |
| not |
運算子 (布爾) |
| object |
向後相容 (類) |
| of |
語句 (case) |
| on |
語句 (異常處理) |
| or |
運算子 (布爾) |
| out |
指令 (參數) |
| overload |
函數指令 |
| override |
函數指令 |
| package |
程式結構 (控制項包) |
| packed |
指令 (記錄) |
| pascal |
函數調用協定 |
| private |
訪問類別符 (class) |
| procedure |
聲明 |
| program |
程式結構 |
| property |
聲明 |
| protected |
訪問類別符 (類) |
| public |
訪問類別符 (類) |
| published |
訪問類別符 (類) |
| raise |
語句 (異常處理) |
| read |
屬性類別符 |
| readonly |
dispatch 介面類別符 |
| record |
類型 |
| register |
函數調用協定 |
| reintroduce |
函數指令 |
| repeat |
語句 |
| requires |
程式結構 (控制項包) |
| resident |
指令 (函數) |
| resourcestring |
類型 |
| safecall |
函數調用協定 |
| set |
類型 |
| shl |
運算子 (數學) |
| shr |
運算子 (數學) |
| stdcall |
函數調用協定 |
| stored |
指令 (屬性) |
| string |
類型 |
| then |
語句 (if) |
| threadvar |
聲明 |
| to |
語句 (for) |
| try |
語句 (異常處理) |
| type |
聲明 |
| unit |
單元結構 |
| until |
語句 |
| uses |
單元結構 |
| var |
聲明 |
| virtual |
指令 (方法) |
| while |
語句 |
| with |
語句 |
| write |
屬性類別符 |
| writeonly |
dispatch 介面類別符 |
| xor |
運算子 (布爾) |
運算式和運算子
建立運算式沒有通用的方法,因為要取決於所用的運算子,Pascal包括有邏輯運算子、算術運算子、布林運算子、關係運算子和集合運算子等等。運算式可用於確定賦給一個變數的值、計算函數或過程的參數、或者判斷一個條件,運算式也可以包含函數調用。運算式是對一個標識符的值而不是標識符本身進行運算。
所有程式設計語言中的運算式都是常量、變數、數值、運算子和函數值的合法組合。運算式可以傳遞給過程或函數的值參,但不能傳遞給過程或函數中的引用參數。
運算子及其優先順序
如果你以前寫過程式,那麼你已經知道運算式是什麼了。這裡我專門講一下Pascal 運算子的特殊部分:運算子的優先順序。表2.2中按優先順序分組列出了Pascal語言的運算子。
與大多數程式設計語言相反,Pascal語言中and和or運算子的優先順序比關係運算子高。因此,如果你的代碼為a < b and c < d,編譯器首先會編譯and運算子,由此導致編譯出錯。為此你應該把每個 < 運算式用小括弧括起來: (a < b) and (c < d)。
同一種運算子用於不同資料類型時它的作用不同。例如,運算子 + 可以計算兩個數位和、串連兩個字串、求兩個集合的並集、甚至給PChar 指標加一個位移量。然而,你不能象在C語言中那樣將兩個字元相加。
另一個特殊的運算子是 div。在Pascal 中,你能用 / 計算兩個數字(實數或整數)的商,而且你總能得到一個實型結果。如果計算兩個整數的商並想要一個整型結果,那麼就需要用 div 運算子。
表 2.2: Pascal語言中的運算子及其優先順序
| 單目運算子 (最高優先順序) |
| @ |
取變數或函數的地址(返回一個指標) |
| not |
邏輯取反或按位取反 |
| 乘除及按位元運算符 |
| * |
相乘或集合交集 |
| / |
浮點相除 |
| div |
整數相除 |
| mod |
模數 (整數相除的餘數) |
| as |
程式運行階段類型轉換 (RTTI運算子) |
| and |
邏輯或按位求和 |
| shl |
按位左移 |
| shr |
按位右移 |
| 加減運算子 |
| + |
相加、集合并集、字串串連或指標增加一個位移量 |
| - |
相減、集合差集或指標減少一個位移量 |
| or |
邏輯或按位或運算 |
| xor |
邏輯或按位異或運算 |
| 關係及比較子(最低優先順序) |
| = |
判斷是否相等 |
| <> |
判斷是否不相等 |
| < |
判斷是否小於 |
| > |
判斷是否大於 |
| <= |
判斷是否小於或等於,或是否是一個集合的子集 |
| >= |
判斷是否大於或等於,或是否是一個集合的父集 |
| in |
判斷是否是集合成員 |
| is |
判斷對象是否類型相容 (又一個RTTI運算子) |
集合運算子
集合運算子包括並(+)、差(-)、交(*)、成員檢測(in),及一些關係運算子。要把一個元素添加到集合中,你可以採用集合并運算。下面是一個選擇字型的Delphi 例子:
Style := Style + [fsBold];Style := Style + [fsBold, fsItalic] - [fsUnderline];
另一種方法是利用標準流程Include 和Exclude,它們效率更高(但不能用於控制項的集合類型屬性,因為只能操縱一個元素):
Include (Style, fsBold);
結束語
從上面內容我們已經瞭解了Pascal 程式的基本布局,下面開始探究它的細節。先從預定義和自訂資料類型開始,然後是利用關鍵片語織編程語句。