共用方式為


建構函式 (F#)

本主題描述如何定義及使用建構函式,以建立及初始化類別和結構物件。

類別物件的建構

類別型別的物件都有建構函式。 建構函式有兩種: 一個是主要建構函式,其參數出現在型別名稱後面的括號中。 您可以使用 new 關鍵字指定其他選擇性建構函式。 任何這類的建構函式都必須呼叫主要建構函式。

主要建構函式包含出現在類別定義開頭的 let 和 do 繫結。 let 繫結會宣告類別的私用欄位和方法;do 繫結則會執行程式碼。 如需類別建構函式中 let 繫結的詳細資訊,請參閱類別中的 let 繫結 (F#)。 如需建構函式中 do 繫結的詳細資訊,請參閱類別中的 do 繫結 (F#)

無論您要呼叫的建構函式是主要建構函式還是其他建構函式,都可以使用 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 關鍵字 (F#)

建構函式中的執行副作用

類別中的主要建構函式可以執行 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.

建構函式中的自我識別項

在其他成員中,您可以為每個成員定義中的目前物件提供名稱, 也可以緊接在建構函式參數後面使用 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")

靜態建構函式或型別建構函式

除了指定建立物件的程式碼之外,在型別第一次用於在型別層級執行初始設定之前先執行的類別型別中,也可以撰寫靜態 let 和 do 繫結。 如需詳細資訊,請參閱類別中的 let 繫結 (F#)類別中的 do 繫結 (F#)

請參閱

其他資源

成員 (F#)