显式字段: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#)。