显式字段:val 关键字 (F#)

val 关键字用于在类类型或结构类型中声明字段,而无需将其初始化。 通过此方式声明的字段称作“显式字段”。 为 val 关键字的另一个使用与声明自动实现的属性的 member 关键字结合使用。 有关自动实现的属性的更多信息,请参见 属性 (F#)

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

备注

在类类型或结构类型中,定义的字段的常见方式是使用 let 绑定。 但是,必须将 let 绑定作为类构造函数的一部分进行初始化,不过并不总是能够或者需要做到这一点。 在需要未初始化的字段时,可以使用 val 关键字。

显式字段可以使静态的,也可以是非静态的。 access-modifier 可以是 public、private 或 internal。 默认情况下,显式字段是公共的。 这与类中的 let 绑定不同,后者始终是私有的。

对于具有主构造函数的类类型中的显式字段,DefaultValue 特性是必需的。 此特性指定将字段初始化为零。 字段的类型必须支持零初始化。 如果类型为下列内容之一,则支持零初始化:

  • 具有零值的基元类型。

  • 支持将 null 值作为正常值、异常值或值的表示形式的类型。 其中包括类、元组、记录、函数、接口、.NET 引用类型、unit 类型和可区分联合类型。

  • .NET 值类型。

  • 其字段都支持默认零值的结构。

警告

请注意 .NET Framework命名空间 System.ComponentModel 包含具有相同名称的特性。有关此属性的信息,请参见 DefaultValueAttribute

下面的代码演示显式字段的用法以及具有主构造函数的类中的 let 绑定,以便进行比较。 请注意,let 绑定的字段 myInt1 是私有的。 在从成员方法引用 let 绑定的字段 myInt1 时,不需要自我标识符 this。 但在引用显式字段 myInt2 和 myString 时,需要自我标识符。

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。

显式字段不能用于例程。 通常,如果可能,您应使用某个类中的 let 绑定而不是显式字段。 显式字段在某些互操作性方案中很有用,例如,您需要定义一个架构,并将在对本地 API 的平台 invoke 调用或在 COM 互操作方案中使用这个架构时。 有关更多信息,请参见外部函数 (F#)。 在另一种情况下,也可能需要使用显式字段,即您在处理一个 F# 代码生成器,而这个代码生成器发出没有主构造函数的类。 对于线程静态变量或类似构造,显式字段也很有用。 有关更多信息,请参见 ThreadStaticAttribute

在关键字 member val 一起出现在类型定义时,它是一个自动实现的属性的定义。 有关更多信息,请参见 属性 (F#)

请参见

参考

属性 (F#)

类中的 let 绑定 (F#)

其他资源

成员 (F#)