显式字段:val 关键字 (F#)
val 关键字用于在类类型或结构类型中声明字段,而无需将其初始化。 通过此方式声明的字段称作“显式字段”。
[ static ] val [ mutable ] [ access-modifier ] field-name : type-name
备注
在类类型或结构类型中,定义的字段的常见方式是使用 let 绑定。 但是,必须将 let 绑定作为类构造函数的一部分进行初始化,不过并不总是能够或者需要做到这一点。 在需要未初始化的字段时,可以使用 val 关键字。
显式字段可以使静态的,也可以是非静态的。 access-modifier 可以是 public、private 或 internal。 默认情况下,显式字段是公共的。 这与类中的 let 绑定不同,后者始终是私有的。
对于具有主构造函数的类类型中的显式字段,DefaultValue 特性是必需的。 此特性指定将字段初始化为零。 字段的类型必须支持零初始化。 如果类型为下列内容之一,则支持零初始化:
具有零值的基元类型。
支持将 null 值作为正常值、异常值或值的表示形式的类型。 其中包括类、元组、记录、函数、接口、.NET 引用类型、unit 类型和可区分联合类型。
.NET 值类型。
其字段都支持默认零值的结构。
下面的代码演示显式字段的用法以及具有主构造函数的类中的 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。