共用方式為


明確欄位:val 關鍵字

val 關鍵字用來宣告位置以儲存類別中或結構類型中的值,但不初始化。 以這種方式宣告的儲存位置稱為明確欄位。 關鍵詞的另 val 一個用法是搭配 member 關鍵詞來宣告自動實作的屬性。 如需自動實作屬性的詳細資訊,請參閱 屬性

語法

val [ mutable ] [ access-modifier ] field-name : type-name

備註

在類別或結構類型中定義欄位通常是使用 let 繫結。 不過,let 繫結必須在類別建構函式中初始化,但不一定總是可行、必要或適合。 當您想要未初始化的欄位時,您可以使用 val 關鍵字。

明確欄位可以是靜態或非靜態。 access-modifier 可以是 publicprivateinternal。 根據預設,明確欄位是 public。 這不同於類別中永遠是 private 的 let 繫結。

在具有主要建構函式的類別型別中,明確欄位需要 DefaultValue 屬性。 這個屬性指定欄位初始化為零。 欄位的類型必須支援零初始化。 下列類型支援零初始化:

  • 具有零值的基本類型。
  • 支援 null 值的類型,可能為正常值、異常值或值的一種表示法。 這包括類別、Tuple、記錄、函式、介面、.NET 參考類型、unit 類型,以及差別聯集類型。
  • .NET 實值類型。
  • 所有欄位都支援預設零值的一種結構。

例如,稱為 someField 的不可變動欄位在 .NET 編譯表示法中有一個名稱為 someField@ 的支援欄位,您可以使用名為 someField 的屬性來存取儲存的值。

對於可變動欄位,.NET 編譯表示法是 .NET 欄位。

警告

.NET Framework 命名空間 System.ComponentModel 包含具有相同名稱的屬性。 如需此屬性的詳細資訊,請參閱 DefaultValueAttribute

下列程式碼示範在具有主要建構函式的類別中使用明確欄位,也示範 let 繫結,方便對照。 請注意,let 繫結的欄位 myInt1 是 private。 從成員方法參考 let 繫結欄位 myInt1 時,不需要自我識別項 this。 但是,當您參考明確欄位 myInt2myString 時,需要自我識別項。

type MyType() =
    let mutable myInt1 = 10
    [<DefaultValue>] val mutable myInt2 : int
    [<DefaultValue>] val mutable myString : string
    member this.SetValsAndPrint( i: int, str: string) =
       myInt1 <- i
       this.myInt2 <- i + 1
       this.myString <- str
       printfn "%d %d %s" myInt1 (this.myInt2) (this.myString)

let myObject = new MyType()
myObject.SetValsAndPrint(11, "abc")
// The following line is not allowed because let bindings are private.
// myObject.myInt1 <- 20
myObject.myInt2 <- 30
myObject.myString <- "def"

printfn "%d %s" (myObject.myInt2) (myObject.myString)

輸出如下所示:

11 12 abc
30 def

下列程式碼示範在沒有主要建構函式的類別中使用明確欄位。 在此例子中,DefaultValue 屬性不是必要的,但在類型所定義的建構函式中必須初始化所有欄位。

type MyClass =
    val a : int
    val b : int
    // The following version of the constructor is an error
    // because b is not initialized.
    // new (a0, b0) = { a = a0; }
    // The following version is acceptable because all fields are initialized.
    new(a0, b0) = { a = a0; b = b0; }

let myClassObj = new MyClass(35, 22)
printfn "%d %d" (myClassObj.a) (myClassObj.b)

輸出為 35 22

下列程式碼示範在結構中使用明確欄位。 由於結構是實值型別,因此會自動有無參數建構函式將其欄位的值設定為零。 因此,不需要 DefaultValue 屬性。

type MyStruct =
    struct
        val mutable myInt : int
        val mutable myString : string
    end

let mutable myStructObj = new MyStruct()
myStructObj.myInt <- 11
myStructObj.myString <- "xyz"

printfn "%d %s" (myStructObj.myInt) (myStructObj.myString)

輸出為 11 xyz

請注意,如果您要使用不含 mutable 關鍵字的 mutable 欄位來初始化結構,您的指派將會作用於會在指派之後隨即捨棄的結構複本。 因此,您的結構不會變更。

[<Struct>]
type Foo =
    val mutable bar: string
    member self.ChangeBar bar = self.bar <- bar
    new (bar) = {bar = bar}

let foo = Foo "1"
foo.ChangeBar "2" //make implicit copy of Foo, changes the copy, discards the copy, foo remains unchanged
printfn "%s" foo.bar //prints 1

let mutable foo' = Foo "1"
foo'.ChangeBar "2" //changes foo'
printfn "%s" foo'.bar //prints 2

平常不適合使用明確欄位。 一般而言,可能的話,應該在類別中使用 let 繫結,而不是明確欄位。 在某些互通性案例中,例如您需要定義結構供平台叫用呼叫原生 API,或在 COM interop 案例中,明確欄位很有用。 如需詳細資訊,請參閱外部函式。 另一種情況是您使用 F# 程式碼產生器來產生沒有主要建構函式的類別,這時也可能需要明確欄位。 對於執行緒靜態變數或類似的建構,明確欄位也很有用。 如需詳細資訊,請參閱System.ThreadStaticAttribute

當關鍵字 member val 一起出現在類型定義中時,這是自動實作屬性的定義。 如需詳細資訊,請參閱 屬性中定義的介面的私用 C++ 專屬實作。

另請參閱