本文說明如何定義及使用建構函式來建立和初始化類別和結構物件。
類別物件的建構
類別類型的物件具有建構函式。 建構函式有兩種。 其中一個是主要建構函式,其參數會出現在類型名稱之後的括弧中。 您可以選擇性地使用 new 關鍵詞來指定其他建構函式。 任何其他建構函式都必須呼叫主要建構函式。
主要建構函式包含 let 和 do 系結,這些系結會出現在類別定義的開頭。 系 let 結會宣告 類別的私人欄位和方法;系 do 結會執行程序代碼。 如需類別建構函式中系結的詳細資訊 let ,請參閱 let 類別中的系結。 如需建構函式中系結的詳細資訊 do ,請參閱 do 類別中的系結。
不論您想要呼叫的建構函式是主要建構函式還是其他建構函式,您都可以使用 new 運算式、搭配或不使用選擇性 new 關鍵詞來建立物件。 您可以將物件與建構函式自變數一起初始化,方法是依序列出自變數,並以逗號分隔,並以括弧括住,或在括弧中使用具名自變數和值。 您也可以在物件建構期間設定物件的屬性,方法是使用屬性名稱並指派值,就像使用具名建構函式自變數一樣。
下列程式代碼說明具有建構函式和各種建立物件的方法的類別:
// This class has a primary constructor that takes three arguments
// and an additional constructor that calls the primary constructor.
type MyClass(x0, y0, z0) =
let mutable x = x0
let mutable y = y0
let mutable z = z0
do
printfn "Initialized object that has coordinates (%d, %d, %d)" x y z
member this.X with get() = x and set(value) = x <- value
member this.Y with get() = y and set(value) = y <- value
member this.Z with get() = z and set(value) = z <- value
new() = MyClass(0, 0, 0)
// Create by using the new keyword.
let myObject1 = new MyClass(1, 2, 3)
// Create without using the new keyword.
let myObject2 = MyClass(4, 5, 6)
// Create by using named arguments.
let myObject3 = MyClass(x0 = 7, y0 = 8, z0 = 9)
// Create by using the additional constructor.
let myObject4 = MyClass()
輸出如下所示:
Initialized object that has coordinates (1, 2, 3)
Initialized object that has coordinates (4, 5, 6)
Initialized object that has coordinates (7, 8, 9)
Initialized object that has coordinates (0, 0, 0)
結構建構
結構會遵循類別的所有規則。 因此,您可以擁有主要建構函式,而且可以使用 來提供其他建構函式 new。 不過,結構與類別之間有一個重要的差異:結構可以有無參數建構函式(也就是沒有自變數的建構函式),即使未定義主要建構函式也一樣。 無參數建構函式會將所有字段初始化為該類型的預設值,通常是零或它的對等專案。 您為結構定義的任何建構函式都必須至少有一個自變數,因此它們不會與無參數建構函式衝突。
此外,結構通常會有使用 關鍵詞建立的 val 字段;類別也可以有這些欄位。 使用 關鍵詞定義 val 欄位的結構和類別也可以使用記錄表示式,在其他建構函式中初始化,如下列程式代碼所示。
type MyStruct =
struct
val X : int
val Y : int
val Z : int
new(x, y, z) = { X = x; Y = y; Z = z }
end
let myStructure1 = new MyStruct(1, 2, 3)
如需詳細資訊,請參閱 明確字段: val 關鍵詞。
在建構函式中執行副作用
類別中的主要建構函式可以在系結中 do 執行程序代碼。 不過,如果您需要在額外的建構函式中執行程序代碼,而不需系 do 結,該怎麼辦? 若要這樣做,請使用 then 關鍵詞。
// Executing side effects in the primary constructor and
// additional constructors.
type Person(nameIn : string, idIn : int) =
let mutable name = nameIn
let mutable id = idIn
do printfn "Created a person object."
member this.Name with get() = name and set(v) = name <- v
member this.ID with get() = id and set(v) = id <- v
new() =
Person("Invalid Name", -1)
then
printfn "Created an invalid person object."
let person1 = new Person("Humberto Acevedo", 123458734)
let person2 = new Person()
主要建構函式的副作用仍會執行。 因此,輸出如下所示:
Created a person object.
Created a person object.
Created an invalid person object.
then當出現在其他建構函式主體中時,do關鍵詞之所以需要,而不是另一個do關鍵詞,而是具有分隔 unit-returning 表達式的標準意義。 它只在主要建構函式的內容中具有特殊意義。
建構函式中的自我標識碼
在其他成員中,您可以在每個成員的定義中提供目前對象的名稱。 您也可以使用 as 緊接在建構函式參數之後的 關鍵詞,將自我標識元放在類別定義的第一行。 下列範例說明此語法。
type MyClass1(x) as this =
// This use of the self identifier produces a warning - avoid.
let x1 = this.X
// This use of the self identifier is acceptable.
do printfn "Initializing object with X =%d" this.X
member this.X = x
在額外的建構函式中,您也可以將 子句放在 as 建構函式參數之後,以定義自我標識符。 下列範例說明此語法:
type MyClass2(x : int) =
member this.X = x
new() as this = MyClass2(0) then printfn "Initializing with X = %d" this.X
當您嘗試在物件完全定義之前使用 物件時,可能會發生問題。 因此,使用自我標識碼可能會導致編譯程式發出警告,並插入額外的檢查,以確保對象成員在初始化物件之前不會存取。 您應該只在主要建構函式的系結中使用 do 自我標識符,或是在其他建構函式中的 關鍵詞之後 then 使用。
自我識別碼的名稱不一定是 this。 它可以是任何有效的標識碼。
在初始化時將值指派給屬性
您可以將表單 property = value 指派清單附加至建構函式的自變數清單,以將值指派給初始化程式代碼中的類別物件屬性。 如下列程式代碼範例所示:
type Account() =
let mutable balance = 0.0
let mutable number = 0
let mutable firstName = ""
let mutable lastName = ""
member this.AccountNumber
with get() = number
and set(value) = number <- value
member this.FirstName
with get() = firstName
and set(value) = firstName <- value
member this.LastName
with get() = lastName
and set(value) = lastName <- value
member this.Balance
with get() = balance
and set(value) = balance <- value
member this.Deposit(amount: float) = this.Balance <- this.Balance + amount
member this.Withdraw(amount: float) = this.Balance <- this.Balance - amount
let account1 = new Account(AccountNumber=8782108,
FirstName="Darren", LastName="Parker",
Balance=1543.33)
下列舊版程式代碼說明一個建構函式呼叫中一般自變數、選擇性自變數和屬性設定的組合:
type Account(accountNumber : int, ?first: string, ?last: string, ?bal : float) =
let mutable balance = defaultArg bal 0.0
let mutable number = accountNumber
let mutable firstName = defaultArg first ""
let mutable lastName = defaultArg last ""
member this.AccountNumber
with get() = number
and set(value) = number <- value
member this.FirstName
with get() = firstName
and set(value) = firstName <- value
member this.LastName
with get() = lastName
and set(value) = lastName <- value
member this.Balance
with get() = balance
and set(value) = balance <- value
member this.Deposit(amount: float) = this.Balance <- this.Balance + amount
member this.Withdraw(amount: float) = this.Balance <- this.Balance - amount
let account1 = new Account(8782108, bal = 543.33,
FirstName="Raman", LastName="Iyer")
繼承類別中的建構函式
從具有建構函式的基類繼承時,您必須在 inherit 子句中指定其自變數。 如需詳細資訊,請參閱 建構函式和繼承。
靜態建構函式或類型建構函式
除了指定建立對象的程式代碼之外,靜態 let 和 do 系結還可以在類別類型中撰寫,這些類型會在類型第一次用來在型別層級執行初始化之前執行。 如需詳細資訊,請參閱 let 類別中的 系結和 do 類別中的系結。