類中包含字段、方法和屬性(屬性包含事件); 字段是靠方法組織與操作的; 屬性也只是方便和規范了字段與方法的使用.
因此我覺得: 方法是最重要的.
方法無處不在, 它不僅僅存在與類中. 先從非類中的方法談起吧, 因為類中的方法也擁有全部這些特性.
離開類的懷抱, 我們更喜歡把方法叫做過程或函數.
//要點1: 過程用 procedure 定義, 函數用 function 定義; 過程沒有返回值, 函數需要返回值.
procedure MyProc;
begin
ShowMessage('ok');
end;
function MyFun: string;
begin
Result := 'ok';
end;
//要點2: 過程和函數都可以有一個或多個參數; 參數用 ; 號分割
procedure MyProc(i: Integer);
begin
ShowMessage(IntToStr(i));
end;
function MyFun(x: Integer; y: Integer): Integer;
begin
Result := x + y;
end;
//要點3: 在調用時, 參數使用 , 分割的
function MyFun(x: Integer; y: Integer): Integer;
begin
Result := x + y;
end;
{調用}
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
i := MyFun(1,2);
end;
//要點4: 多個相同類型的參數可以簡化寫法
function MyFun(str: string; x,y,z: Integer): string;
begin
Result := str + IntToStr(x + y + z);
end;
//要點5: 函數的返回值可以使用 Result , 也可以使用函數名(但不提倡)
function MyFun1(x,y: Integer): Integer;
begin
Result := x + y;
end;
function MyFun2(x,y: Integer): Integer;
begin
MyFun2 := x + y;
end;
//要點6: Result 可以參與運算, "函數名"不可以
function MyFun(x,y: Integer): Integer;
begin
Result := x + y;
Result := Result * 2;
end;
//要點7: 不僅如此, Result 還有更靈活的運用
function MyFun(b: Byte): Char;
begin
//Result := Char(b); {我們當然可以這樣寫}
Byte(Result) := b; {這樣也行}
end;
{System 中就有這樣一個函數}
function TObject.ClassType: TClass;
begin
Pointer(Result) := PPointer(Self)^;
end;
//要點8: 忘了寫返回值的函數, 也可以當過程用(沒有人會這樣做, 但 Delphi 竟然也允許)
function MyFun(var x: Integer): string;
begin
x := x + 1;
end;
{調用}
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
i := 2;
MyFun(i);
ShowMessage(IntToStr(i)); {3}
end;
//要點9: 沒有參數的過程或函數, 在調用時可以省略 (); 也可以帶著
function MyFun: string;
begin
Result := 'ok';
end;
{調用}
procedure TForm1.Button1Click(Sender: TObject);
var
s: string;
begin
s := MyFun;
ShowMessage(s); {ok}
s := MyFun();
ShowMessage(s); {ok}
end;
//要點10: 過程和函數都可以有一個或多個默認參數; 但必須在非默認參數後面
function MyFun(s1: string; s2: string='好人'): string;
begin
Result := s1 + s2;
end;
{調用}
procedure TForm1.Button1Click(Sender: TObject);
var
str1,str2: string;
begin
str1 := '萬一';
str2 := '壞蛋';
ShowMessage(MyFun(str1)); {萬一好人}
ShowMessage(MyFun(str1,str2)); {萬一壞蛋}
end;
//要點11: 參數可以分為: 默認參數(傳值)、var(傳址)、out(輸出)、const(常數)四類
{默認參數是傳值, 不會被改變}
function MyF1(x: Integer): Integer;
begin
Inc(x);
Result := x;
end;
{var參數是傳址, 會被改變}
function MyF2(var x: Integer): Integer;
begin
Inc(x);
Result := x;
end;
{out參數是為支持Com的, 和 var 的結果是一樣的, 一般我們用不著它}
function MyF3(out x: Integer): Integer;
begin
Inc(x);
Result := x;
end;
{const參數是絕對不可以賦值的, 這是被編譯器優化的方式, 盡量多用}
function MyF4(const x: Integer): Integer;
begin
//Inc(x); {這句會出錯, 因為帶 const 前綴的參數是不可以更改的}
Result := x;
end;
//調用測試
procedure TForm1.Button1Click(Sender: TObject);
var
a: Integer;
begin
a := 6; MyF1(a);
ShowMessage(IntToStr(a)); //6
a := 6; MyF2(a);
ShowMessage(IntToStr(a)); //7
a := 6; MyF3(a);
ShowMessage(IntToStr(a)); //7
a := 6; MyF4(a);
ShowMessage(IntToStr(a)); //6
end;
//要點12: implementation 區中的過程或函數, 只能在本單元調用
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{implementation 區中的過程或函數, 只能在本單元調用}
function MyFun(x,y: Integer): Integer;
begin
Result := x + y;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
i := MyFun(1,2);
end;
end.
//要點13: 需要給其他單元調用, 必須在 interface 聲明, 但必須在 uses 區後面
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
{需要給其他單元調用, 必須在 interface 聲明, 但必須在 uses 區後面}
function MyFun(x,y: Integer): Integer; {函數聲明}
var
Form1: TForm1;
implementation
{$R *.dfm}
function MyFun(x,y: Integer): Integer; {函數實現}
begin
Result := x + y;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
i := MyFun(1,2);
ShowMessage(IntToStr(i)); {3}
end;
end.
//要點14: 如果聲明在 TForm1 類內, 那它就是 TForm1 類的一個方法了
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
function MyFun(x,y: Integer): Integer; {函數聲明在 TForm1 類的體內}
{現在這個函數 MyFun 已經是 TForm1 類的一個方法了}
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{函數在實現區必須有 TForm1. 作為前綴}
function TForm1.MyFun(x,y: Integer): Integer;
begin
Result := x + y;
end;
{調用}
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
i := MyFun(1,2);
ShowMessage(IntToStr(i)); {3}
end;
end.
//要點15: 調用其他單元的函數
//包含函數的單元:
unit Unit2;
interface
function MyFun(x,y: Integer): Integer; {函數必須在接口區聲明}
implementation
function MyFun(x,y: Integer): Integer; {函數必須在函數區實現}
begin
Result := x + y;
end;
end.
//調用函數的單元:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses Unit2; {必須 uses 定義函數的單元}
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
i := MyFun(1,2); {調用函數}
//i := Unit2.MyFun(1,2); {有時為了避免重名, 需要這樣調用}
ShowMessage(IntToStr(i)); {3}
end;
end.
//要點16: 在實現區(implementation), 自定義的方法是有順序的
function MyFunA(x: Integer): Integer;
begin
Result := Sqr(x); {取平方}
//MyFunB(x); {前面的函數不能調用後面的函數}
end;
function MyFunB(x: Integer): Integer;
begin
Result := MyFunA(x) * 2; {可以調用前面的函數 MyFunA}
end;
//要點17: 如果前面的方法要調用後面的方法, 後面的方法需要提前聲明
function MyFunB(x: Integer): Integer; forward; {使用 forward 指示字提前聲明}
function MyFunA(x: Integer): Integer;
begin
Result := MyFunB(x) * 3; {要調用後面的方法, 後面的方法需要提前聲明}
end;
function MyFunB(x: Integer): Integer;
begin
Result := Abs(x);
end;
//要點18: 如果函數在接口區定義了, 就無需用 forward 提前聲明了
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
var
Form1: TForm1;
{現在函數定義在接口區(interface)}
function MyFunA(x: Integer): Integer;
function MyFunB(x: Integer): Integer;
implementation
{$R *.dfm}
function MyFunA(x: Integer): Integer;
begin
Result := MyFunB(x) * 3; {因為在接口區有了聲明, 前面的函數就可以調用後的函數了}
end;
function MyFunB(x: Integer): Integer;
begin
Result := Abs(x);
end;
{調用測試}
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
i := MyFunA(-3);
ShowMessage(IntToStr(i)); {9}
end;
end.
//要點19 : Delphi 支持過程中的方法
procedure TForm1.Button1Click(Sender: TObject);
procedure alert(s: string);
begin
ShowMessage(s);
end;
begin
alert('萬一'); {萬一}
end;
//要點20 : 靜態數組做參數, 不能這樣使用:
function MyFun(arr: array[0..9] of Integer): Integer;var
i: Integer;
begin
Result := 0;
for i in arr do Result := Result + i;
end;
//應該先把數組定義成一個類型
Type
IntArray = array[0..9] of Integer; {先把需要的數組定義成一個類型}
//給一個靜態數組求和的函數
function MyFun(arr: IntArray): Integer;
var
i: Integer;
begin
Result := 0;
for i in arr do Result := Result + i;
end;
{測試}
procedure TForm1.Button1Click(Sender: TObject);
const
intArr: IntArray = (1,2,3,4,5,6,7,8,9,10);
var
x: Integer;
begin
x := MyFun(intArr); {調用函數}
ShowMessage(IntToStr(x)); {55}
end;
深入方法[21] - 開放數組參數
//給一個整型開放數組求和的函數
function MyFun(const arr: array of Integer): Integer;
var
i: Integer;
begin
Result := 0;
for i in arr do Result := Result + i;
end;
{測試1:}
procedure TForm1.Button1Click(Sender: TObject);
var
num: Integer;
begin
num := MyFun([1,2,3]);
ShowMessage(IntToStr(num)); {6}
end;
{測試2:}
procedure TForm1.Button2Click(Sender: TObject);
var
iArr: array of Integer;
i,x: Integer;
begin
SetLength(iArr, 10);
for i := Low(iArr) to High(iArr) do
begin
iArr[i] := i + 1;
end;
x := MyFun(iArr);
ShowMessage(IntToStr(x)); {55}
end;
深入方法[22] - 指針參數
{現在這個函數並沒有 var 前綴, 也就是說參數應該不會被修改的}
function MyFun(p: PInteger): Integer; {PInteger 是 Integer 的指針類型}
begin
p^ := p^ * 2;
Result := p^;
end;
{測試}
procedure TForm1.Button1Click(Sender: TObject);
var
i,x: Integer;
begin
i := 8;
x := MyFun(@i); {調用函數}
ShowMessage(IntToStr(x)); {16}
{現在 i 的值應該不會被修改, 但...}
ShowMessage(IntToStr(i)); {16}
{
沒有 var 或 out 前綴的參數, 應該是傳值的;
有 var 或 out 的參數是傳地址的;
指針就是一個地址, 盡管沒有指定傳地址, 但事實上就是給了一個地址,
所以參數值也會改變!
}
end;
深入方法[23] - 重載
{
{測試}
下面的函數重名, 但參數不一樣, 此類情況必須加 overload 指示字;
調用時, 會根據參數的類型和個數來決定調用哪一個;
這就是重載.
}
function MyFun(s: string): string; overload;
begin
Result := '參數是一個字符串: ' + s;
end;
function MyFun(i: Integer): string; overload;
begin
Result := '參數是一個整數: ' + IntToStr(i);
end;
function MyFun(x,y: Integer): string; overload;
begin
Result := Format('參數是兩個整數: %d 和 %d', [x,y]);
end;procedure TForm1.Button1Click(Sender: TObject);
//另外還要注意關於重載和默認參數的問題, 譬如, 下面的重載是不可行的:
var
str: string;
begin
str := MyFun('萬一');
ShowMessage(str); {參數是一個字符串: 萬一}
str := MyFun(99);
ShowMessage(str); {參數是一個整數: 99}
str := MyFun(6,8);
ShowMessage(str); {參數是兩個整數: 6 和 8}
end;function MyFun(x,y: Integer): string; overload;
{因為當我們這樣調用時: MyFun(a,b); 系統就不知道要調用哪個了!}
begin
Result := IntToStr(x + y);
end;
function MyFun(x: Integer; y: Integer = 1): string; overload;
begin
Result := IntToStr(x + y);
end;
深入方法[24] - 方法是一個指針{自定義過程}procedure MyProc;
深入方法[25] - 使用方法類型//弄明白這一點, 才好使用回調函數
begin
ShowMessage('ok');
end;
{自定義函數}
function MyFun: string;
begin
Result := 'ok';
end;
{讀取它們的指針}
procedure TForm1.Button1Click(Sender: TObject);
var
p: Pointer;
begin
p := @MyProc;
ShowMessage(IntToStr(Integer(p))); {4570984; 這是動態的}
p := @MyFun;
ShowMessage(IntToStr(Integer(p))); {4571008; 這是動態的}
end;{定義方法類型}
深入方法[26] - 回調函數
type
TFunType = function(x: Integer): Integer; {函數類型}
TProcType = procedure(name: string); {過程類型}
{定義一個符合 TFunType 類型的函數}
function MyFun(x: Integer): Integer;
begin
Result := x * 2;
end;
{定義一個符合 TProcType 類型的過程}
procedure MyProc(name: string);
begin
ShowMessage('我是' + name);
end;
{使用}
procedure TForm1.Button1Click(Sender: TObject);
var
Fun : TFunType; {定義一個 TFunType 類型的變量}
Proc: TProcType; {定義一個 TProcType 類型的變量}
begin
Fun := MyFun; {讓變量 Fun 指向和它具有同樣參數和返回值的自定義函數 MyFun}
Proc := MyProc; {讓變量 Proc 指向和它具有同樣參數的自定義過程 MyProc}
{現在這兩個方法的變量 Fun、Proc 可以使用了}
ShowMessage(IntToStr(Fun(4))); {8}
Proc('萬一'); {我是萬一}
end;
//把一個方法當作另一個方法的參數, 就是回調方法, 大家習慣稱作回調函數type
{把函數當作參數, 再定義一個函數}
TFunType = function(i: Integer): Integer; {聲明一個方法類型}
function MyFun(i: Integer): Integer; {建立類型兼容的函數}
begin
Result := i*2;
end;function MyTest(x: Integer; F: TFunType): Integer;
{測試}
begin
Result := F(x);
end;procedure TForm1.Button1Click(Sender: TObject);
深入方法[27] - 遞歸函數:
var
Fun: TFunType; {聲明一個 TFunType 的變量}
i: Integer;
begin
Fun := MyFun; {讓方法變量 Fun 指向和它類型兼容的一個方法}
{測試 Fun; Fun 是一個方法變量, 現在去執行那個方法, 它就可以當作那個方法來使用了}
i := Fun(4);
ShowMessage(IntToStr(i)); //8
{把 Fun 當作參數使用; 把函數當作參數使用, 這就是回調函數}
i := MyTest(4,Fun);
ShowMessage(IntToStr(i)); //8
end;
簡單示例//所謂遞歸函數, 就是自己調用自己的函數, 先來個簡單的例子:{遞歸調用的簡單示例}
{測試}
procedure alert(i: Integer = 1);
begin
ShowMessage(IntToStr(i)); {這是方法的功能}
Inc(i);
if i<10 then
alert(i); {這是方法自調用}
end;procedure TForm1.Button1Click(Sender: TObject);
深入方法[28] - 遞歸函數實例: 搜索當前目錄下的所有嵌套目錄
begin
alert; {會連續彈出 9 個對話框, 分別提示 1..9}
end;
//上面一個例子不能說明遞歸函數的本質, 直接來個實用的函數吧, 剛好要用.unit Unit1;
{測試}
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//列出一個目錄下所有目錄(包括嵌套)的函數
procedure GetDirs(dirName: string; List: TStrings);
var
SRec: TSearchRec; {定義 TSearchRec 結構變量}
dir: string;
const
attr: Integer = faDirectory; {文件屬性常量, 表示這是文件夾}
begin
dirName := ExcludeTrailingBackslash(dirName) + ''; {不知道最後是不是 ; 先去掉, 再加上}
dir := dirName + '*.*'; {加上 ; *.* 或 * 表示所有文件, 系統會把目錄也當作一個文件}
if FindFirst(dir, attr, SRec) = 0 then {開始搜索,並給 SRec 賦予信息, 返回0表示找到第一個}
begin
repeat
if (SRec.Attr = attr) and {如果是文件夾}
(SRec.Name <> '.') and {排除上層目錄}
(SRec.Name <> '..') then {排除根目錄}
begin
List.Add(dirName + SRec.Name); {用List記下結果}
GetDirs(dirName + SRec.Name, List); {這句就是遞歸調用, 如果沒有這句, 只能搜索當前目錄}
end;
until(FindNext(SRec)<>0); {找下一個, 返回0表示找到}
end;
FindClose(SRec); {結束搜索}
end;procedure TForm1.Button1Click(Sender: TObject);
深入方法[29] - 傳址參數不能賦予常量
var
list: TStrings;
begin
list := TStringList.Create;
GetDirs('C:Downloads', list);
Memo1.Lines := list;
list.Free;
end;
end.
{給這個函數可以賦常數變量}
{測試}
function Fun1(x,y: Integer): Integer;
begin
Result := x + y;
end;
{這個函數不能賦予常數變量}
function Fun2(var x,y: Integer): Integer;
begin
Result := x + y;
end;procedure TForm1.Button1Click(Sender: TObject);
var
i,a,b: Integer;
const
j = 6;
k = 8;
begin
i := Fun1(1,2);
ShowMessage(IntToStr(i)); {3}
//i := Fun2(1,2); {這樣是 Fun2 是錯誤的, 它的參數是傳地址的, 必須用變量}
//i := Fun2(j,k); {這樣也不行}
{應該:}
a := 2;
b := 4;
i := Fun2(a,b);
ShowMessage(IntToStr(i)); {6}
end;