delphi的一些語法知識 以及參數傳遞問題,按引用方式傳遞參數,按值方式傳遞參數

//delphi中exit,abort,break,continue 的區別數組

exit: 退出函數體
abort: 遇到異常,安靜處理,就是不顯示不提示
break: 退出當前循環體,包括for ,while, repeat等循環體
continue: 結束循環內的本次處理,繼續從循環體的開始位置繼續執行分佈式

 

Exit 是跳出當前代碼塊,也就是當前函數,跳出後是要繼續向下執行的(若是有後續代碼)。ide

Abort 是從 EAbort 過來的,能夠激發 exception,其實質就是 Abort = RaiseException(),是一個不出現對話框的異常。因此 Abort 的行爲和異常是同樣的,其代碼執行順序也是follow異常的流程。
例如:
try
(1) //執行了
abort;
(2) //不執行
exception
(3) //執行了
end;函數

用 Abort 可以執行 exception 裏邊的代碼,可是若是用 Exit,就直接離開,無論 exception。優化

例如: 
procedure p1;
begin
p2;
p3;
end;
procedure p2;
begin
abort; //exit;
end;
procedure p3;
begin
//showmessage()..
end;spa

若是用 Abort,則執行不到 P3,若是用 Exit 就可以執行到 P3

******************************************************************************指針

在Delphi過程、函數中傳遞參數幾個修飾符爲Const、Var、Out。另外一種不加修飾符的爲默認按值傳遞參數。
1、默認方式以值方式傳遞參數
procedure TForm1.ProcNormal(Value: string);
begin
OrigNum:=Value+' Me';
lblReturn.Caption:=OrigNum;//OrigNum爲'Hello Me'
lblOrig.Caption:=Value;//Value爲'Hello'
end;orm

調用:
OrigNum:='Hello';
ProcNormal(OrigNum);對象

2、以Const方式傳遞參數,這個參數在調用過程當中不能改變,而且這種方式會被編譯器優化,通常建議儘量地使用這種方式。
procedure TForm1.ProcConst(const Value: string);
begin
OrigNum:=Value+' Me';
lblReturn.Caption:=OrigNum;//爲'Hello Me‘
lblOrig.Caption:=Value;//爲'Hello Me'
end;內存

3、按引用方式傳遞參數
procedure TForm1.ProcRef(var value: string);
begin
OrigNum:=Value+' Me';
lblReturn.Caption:=OrigNum;//爲'Hello Me‘
lblOrig.Caption:=Value;//爲'Hello Me'
end;

4、按Out方式傳遞參數,這個方式傳遞參數時,參數能夠不被初始化,即便有值也被忽視,它通常用於輸出,它能夠實如今一個過程當中返回多個值,咱們一般在分佈式對象模型,如COM中使用它。
procedure TForm1.ProcOut(out Value: string);
begin
OrigNum:=Value+' Me';
lblReturn.Caption:=OrigNum;//爲'Me'
lblOrig.Caption:=Value;//爲'Me'
end;

5、無類型參數,這是一種較爲特殊的方法,參數的類型不肯定,只能用Const、Var、Out修飾,不能用於值方式傳遞參數,具體使用示例以下:
procedure TForm1.ProcUntype(const Value);
begin
OrigNum:=string(Value)+' Me';
lblReturn.Caption:=OrigNum;//爲'Hello Me'
lblOrig.Caption:=string(Value);//爲'Hello Me'
end;

6、默認參數,即若是此參數在調用時未提供時,將使用默認值。
procedure TForm1.ProcDefault(const Value, constDefaultValue:string=' 123');
begin
OrigNum:=Value+' Me'+DefaultValue;
lblReturn.Caption:=OrigNum;//爲'Hello Me 123'
lblOrig.Caption:=Value;// 爲'Hello Me 123'
end;

7、開放數組參數,即參數數組的元素個數不肯定。
procedure TForm1.ProcArray(const Value: array of string);
var
i:Integer;
begin
for i:=Low(Value) to High(Value) do
OrigNum:=OrigNum+Value[i];//調用後爲'Hello abc dbd'
lblReturn.Caption:=OrigNum;
end;

調用:

OrigNum:='Hello';
ProcArray([' abc ',' dbd']);

8、無類型開放數組參數,即類型及元素個數皆不肯定。在WIN32平臺中,這個參數的類型實際爲array ofTVarRec,其使用示例以下:
procedure TForm1.ProcArrayConst(const Value: array of const);
var
i:Integer;
begin
for i:=Low(Value) to High(Value) do
with Value[i] do
case VType of
vtAnsiString: OrigNum:= OrigNum+String(VAnsiString);
vtInteger: OrigNum:=OrigNum+IntToStr(VInteger);
vtBoolean: OrigNum := OrigNum + BoolToStr(VBoolean);
vtChar: OrigNum := OrigNum + VChar;
vtExtended: OrigNum := OrigNum + FloatToStr(VExtended^);
vtString: OrigNum := OrigNum + VString^;
vtPChar: OrigNum := OrigNum + VPChar;
vtObject: OrigNum := OrigNum + VObject.ClassName;
vtClass: OrigNum := OrigNum + VClass.ClassName;
vtCurrency: OrigNum := OrigNum + CurrToStr(VCurrency^);
vtVariant: OrigNum := OrigNum + string(VVariant^);
vtInt64: OrigNum := OrigNum + IntToStr(VInt64^);
end;
lblReturn.Caption:=OrigNum;//調用後爲'Hello abc 3'
end;

調用:

OrigNum:='Hello';
ProcArrayConst([' abc ',3]);

以上就是常見幾種傳遞參數的方式。

//另外一篇文章關於delphi參數傳遞的//

 
delphi參數傳遞
 
參數傳遞
    聲明/實現一個過程使用的參數稱爲形式參數(簡稱形參),調用過程時傳入的參數稱爲實際參數(簡稱實參)。
 
{ Info是形參}
 
procedure ShowInfo(Info: String);
begin
  ShowMessage(Info);
end;
 
var
  S: String;
begin
  S := 'lxpbuaa';
  {S是實參}
  ShowInfo(S);
end;
 
參數傳遞分兩種:按值(by val)和引用(by ref)。這兩種方式的本質區別是:
按值傳遞時,形參和實參是兩個變量,它們開始時的值是相同的,即實參的數據被拷貝一份傳遞給了形參。因此此時,形參的改變不會影響到實參。
引用傳遞時,形參和實參是同一個變量,能夠將它們之一看作是另外一個的別名。 因此此時,形參改變時,實參跟着改變。
默認狀況下,參數是按值傳遞的,傳遞的是數據拷貝;若是加了var前綴,則成了引用傳遞。
 
咱們看以下例子:
procedure TForm1.ByVal(I: Integer);     {按值傳遞I}
begin
  ShowMessage(IntToStr(Integer(@I)));    
  {取得形參所在地址。你會發現它和實參地址是不一樣的,由於此時實參和形參是不一樣的兩個變量}
  I := I + 1;
end;
 
procedure TForm1.ByRef(var I: Integer); {引用傳遞I}
begin
  ShowMessage(IntToStr(Integer(@I)));    
  {取得形參所在地址。你會發現它和實參地址是相同的,由於此時實參和形參是同一個變量}
  I := I + 1;
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
begin
  I := 1;
  ShowMessage(IntToStr(Integer(@I)));        {取得實參所在地址}
  ByVal(I);  { I =1}
 Showmessage(i); {i:=1;實參沒有變}
  ByRef(I);  { I =2}
 showmessage(i); {i:=2,實參改變了}
end;
 
按值傳遞的參數能夠指定默認值,好比上面的ByVal能夠是這樣:
procedure ByVal(I: Integer = 0);
調用它時能夠省掉有默認值的參數:ByVal。帶默認值的參數必須位於參數列表的最後,如:
 
procedure ByVal(I: Integer = 0; B: Boolean);
是不行的,應該改成:
procedure ByVal(B: Boolean; I: Integer = 0);
 
由於默認值必須是一個常數表達式,因此dynamic-array、procedural、class、class-reference和interface等參數只能指定nil默認值;而record、variant、file和static-array等類型的參數則根本不能指定默認值。
 
若是按值傳遞一個指針類型的參數,狀況會變得複雜而又頗有意思。此時,實際傳遞的是什麼呢?是實際數據的拷貝嗎?不,是指針的拷貝,也就是說形參和實參是兩個指針,不過這兩個指針指向了相同地址。因此這時候,形參和實參能夠共享它們指向地址中的數據,但若是改變了形參的指針指向,實參的指針指向不能跟着改變。那麼總結一下,就是:按值傳遞指針參數時,實參和形參能夠共享指針指向地址中的數據,可是不能共享指針自己的指向。而引用傳遞時,由於實參和形參是同一個變量,所以實現徹底共享。看下面的例子:
 
procedure TForm1.ByVal(Obj: TObject);
begin
  Obj := Button1;    
  {改變形參指針指向,實參的指針指向不會跟着改變,由於它們是兩個變量。若是僅僅是改變Obj的屬性而不改變指向,則實參的屬性會跟着改變}
end;
 
procedure TForm1.ByRef(var Obj: TObject);
begin
  Obj := Button1;        
  {改變形參指針指向,實參的指針指向跟着改變,由於它們是同一個變量}
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
  Obj: TObject;
begin
  Obj := Self;           
  {Self即Form1,因此此時實參Obj的類名(ClassName)是"TForm1"}
  ByVal(Obj);                    {按值傳遞指針變量Obj}
 
  ShowMessage(Obj.ClassName);    {顯示類名"TForm1"}
  ByRef(Obj);                       {引用傳遞指針變量Obj}
  ShowMessage(Obj.ClassName);    {顯示類名"TButton1"}
end;
 
上面講了這麼多,最根本的仍是一句話:按值傳遞時,形參和實參是兩個變量;引用傳遞時,形參和實參是同一個變量。抓住這句話,就等於抓住了一切。(ps:關鍵總結):
相信你還看到過以下格式的參數聲明:
function CompareStr(const S1, S2: string): Integer;
function TryStrToInt(const S: string; out Value: Integer): Boolean;
其中使用了const和out關鍵字。若是你沒有看到過這樣的聲明,也沒關係,它們是真實存在的。
const聲明的參數是按值傳遞的,並且形參不能被改變。
out聲明的參數是引用傳遞的,主要用於定義輸出參數,也就是說不須要輸入值(即實參不須要初始化),實參傳遞給形參的值被忽略。
若是用const修飾指針參數,那麼只能經過形參修改指針地址裏的數據而不能修改指針自己的指向。例如對於一個const對象參數,能夠修改其屬性,可是不能將它指向其餘對象。例如:
 
procedure ShowInfo(const Form: TForm);
begin
  {如下一句不能經過,編譯器提示:[Error] Unit1.pas(28): Left side  cannot be assigned to}
  {Form := Form1;}
  {可是經過其屬性或者方法修改隸屬於Form的數據}
  Form.Caption := 'lxpbuaa';
  ShowMessage(Form.Caption);
end;
 
在本小節的最後,還不得不說起一種很特殊的參數類型:無類型參數(Untyped parameters)。
聲明時沒有指定數據類型的參數稱爲無類型參數。所以,從語法上講,無類型參數能夠接收任何類型的數據。
無類型參數必須加const、out或var前綴;無類型參數不能指定默認值。
 
如如下一些Delphi定義的過程都使用了無類型參數:
 
procedure SetLength(var S; NewLength: Integer);       {參數S}
procedure Move(const Source;var Dest;Count:Integer);   {參數Source、Dest}
procedure TStream.WriteBuffer(const Buffer; Count: Longint);{參數Buffer}
 
所謂無類型參數能夠接收任何類型的值,只是從語法角度而言的。或者說,理論上咱們能夠實現一個可使用任何類型變量做爲參數的過程,可是實際上沒有必要,也不可能作到。
打個比方說,咱們想造一輛能夠裝載任何物體的汽車。由於是「任何物體」,因此物體多是任何形狀,因而這輛車必須沒有車篷,除了在幾個車輪上鋪一個足夠大(足夠大就已是個大問題了)的平板外,不能再有任何東西。這時候,這個平板就能夠看作是無類型的,由於它上面能夠坐人、擺一張桌子,也能夠趕一些動物上去站着或者躺着。儘管它能夠承載不少種類的東西,可是也是有限制的,好比不能放一座山、也沒法容納1萬頭豬。因此無類型參數的類型每每是有必定限制的。好比SetLength的參數S只能是字符串、動態數組等。
這種限制通常是在過程的實現中完成的,在運行時檢查參數值的實際類型。對於與開發環境關係緊密的參數,限制也能夠構築在編譯器裏。
使用無類型參數的緣由是沒法在聲明時使用一個統一的類型來描述運行時可能的類型,如SetLength的參數S能夠是字符串和動態數組,而並無一個統一的類型來表明字符串和動態數組類型,因此乾脆聲明爲無類型。而將類型限制放到別的地方實現(如編譯器)。例如SetLength的限制規則是寫在編譯器中的,它只能做用於長字符串或者動態數組。你企圖完成下面的功能時:
var
  I: Integer;
begin
  SetLength(I, 10);
end;
 
編譯器編譯時將給出錯誤信息:[Error] Unit1.pas(35): Incompatible types。致使編譯中斷。
 
小結
本小節的內容比較重要,重點是理解參數按值傳遞和引用傳遞的本質:按值傳遞時,形參和實參是兩個變量;引用傳遞時,形參和實參是同一個變量。
 
聲明指令
聲明一個過程,可使用register、pascal、cdecl、stdcall和safecall指令來指定參數傳遞順序和參數內存管理方式,從而影響過程的運做。如:
function MyFunction(X, Y: Integer): Integer; cdecl;
 
這五個指令具備不一樣含義,如表3-1所示。
 
表3-1   五個指令的不一樣含義
 
 指令     參數存放位置      參數傳遞順序   參數內存管理        適用地點
 register  CPU寄存器      從左到右      被調用者   默認.published屬性存取                                                                 方法 必須使用
 pascal         棧           從左到右      被調用者    向後兼容,再也不使用
 cdecl          棧           從右到左      調用者      調用C/C++共享庫
 stdcall         棧           從右到左      被調用者    API調用,如回調函數
 safecall        棧           從右到左      被調用者    API調用,如回調函數。雙
 
在一些源代碼(包括Delphi自帶的VCL源代碼)中,你還可能看到near、far、export以及inline、assemble等指令,它們是爲了和16位Windows系統或者早期Pascal/Delphi兼容,在目前的Delphi版本中,已經不具備任何意義,因此在新的開發中不要再使用。
相關文章
相關標籤/搜索