结构
“结构”是一种紧凑对象类型,对于数据量较少且行为简单的类型来说,可能比类更有效。
语法
[ attributes ]
type [accessibility-modifier] type-name =
struct
type-definition-elements-and-members
end
// or
[ attributes ]
[<StructAttribute>]
type [accessibility-modifier] type-name =
type-definition-elements-and-members
备注
结构是“值类型”,也就是说它们直接存储在堆栈上,或者用作字段或数组元素内联在父类型中。 与类和记录不同,结构具有按值传递语义。 这意味着它们主要用于经常访问和复制的少量聚合数据。
在前面的语法中,将显示两个窗体。 第一个窗体不是轻量级语法,但其仍然经常使用,因为当使用 struct
和 end
关键字时,你可以忽略第二个窗体中出现的 StructAttribute
特性。 你可以将 StructAttribute
缩写为 Struct
。
之前语法中的 type-definition-element -and-members 表示成员声明和定义。 结构可以具有构造函数以及可变和不可变字段,并且可以声明成员和接口实现。 有关详细信息,请参见成员。
结构不能参与继承、不能包含 let
或 do
绑定、不能以递归方式包含其自身类型的字段(但可以包含引用其自身类型的引用单元格)。
由于结构不允许 let
绑定,你必须通过使用 val
关键字在结构中声明字段。 val
关键字定义字段及其类型,但不允许初始化。 相反,val
声明会初始化零或 null。 因此,具有隐式构造函数(即,在声明中的结构名称后直接给定参数)的结构要求使用 val
特性批注 DefaultValue
声明。 具有定义构造函数的结构仍支持零初始化。 因此,DefaultValue
特性是此类零值对字段有效的声明。 由于此类型上不允许 let
和 do
绑定,结构的隐式构造函数不执行任何操作,但所传入的隐式构造函数参数值作为私有字段提供。
显式构造函数可能涉及字段值的初始化。 当你的结构具有显式构造函数时,它仍支持零初始化;但是,由于它与显式构造函数冲突,请勿在 DefaultValue
声明上使用 val
特性。 有关 val
声明的详细信息,请参阅显式字段:val
关键字。
结构上允许特性和可访问性修饰符,并遵循与其他类型相同的规则。 有关详细信息,请参阅特性和访问控制。
以下代码示例说明结构定义。
// In Point3D, three immutable values are defined.
// x, y, and z will be initialized to 0.0.
type Point3D =
struct
val x: float
val y: float
val z: float
end
// In Point2D, two immutable values are defined.
// It also has a member which computes a distance between itself and another Point2D.
// Point2D has an explicit constructor.
// You can create zero-initialized instances of Point2D, or you can
// pass in arguments to initialize the values.
type Point2D =
struct
val X: float
val Y: float
new(x: float, y: float) = { X = x; Y = y }
member this.GetDistanceFrom(p: Point2D) =
let dX = (p.X - this.X) ** 2.0
let dY = (p.Y - this.Y) ** 2.0
dX + dY |> sqrt
end
ByRefLike 结构
你可以自定义可遵循类似 byref
的语义的结构:有关详细信息,请参阅 Byrefs。 这通过 IsByRefLikeAttribute 属性来完成:
open System
open System.Runtime.CompilerServices
[<IsByRefLike; Struct>]
type S(count1: Span<int>, count2: Span<int>) =
member x.Count1 = count1
member x.Count2 = count2
IsByRefLike
并不表示 Struct
。 这两者必须都存在于类型中。
F# 中类似 byref
的结构是堆栈绑定值类型。 永远不会在托管堆上分配它。 类似 byref
的结构可用于高性能编程,因为它是通过一组有关生存期和非捕获的强检查强制执行的。 规则包括:
- 它们可用作函数参数、方法参数、局部变量、方法返回。
- 它们不能是类或普通结构的静态成员或实例成员。
- 它们不能由任何闭包构造(
async
方法或 Lambda 表达式)捕获。 - 它们不能用作泛型参数。
虽然这些规则施加了非常严格的使用限制,但这样做是为了履行安全地进行高性能计算的承诺。
ReadOnly 结构
可以使用 IsReadOnlyAttribute 特性对结构进行批准。 例如:
[<IsReadOnly; Struct>]
type S(count1: int, count2: int) =
member x.Count1 = count1
member x.Count2 = count2
IsReadOnly
并不表示 Struct
。 必须添加这两者才能得到 IsReadOnly
结构。
使用此特性会发出元数据,告知 F# 和 C# 将其分别视为 inref<'T>
和 in ref
。
在 readonly 结构中定义可变值会产生错误。
结构记录和可区分联合
可以使用 [<Struct>]
特性将记录和可区分联合表示为结构。 请查看每篇文章了解详细信息。