结构

结构是一种紧凑对象类型,比具有少量数据和简单行为的类型的类更有效。

语法

[ 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

注解

结构是 值类型,这意味着它们直接存储在堆栈上,或者当它们用作字段或数组元素时,它们内联在父类型中。 与类和记录不同,结构具有按值传递的语义。 这意味着它们主要用于经常访问和复制的数据的小型聚合。

在前面的语法中,将显示两种形式。 第一个语法不是轻型语法,但它仍然经常使用,因为在使用 structend 关键字时,可以省略第 StructAttribute 二种形式中显示的属性。 可以缩写 StructAttribute 为仅 Struct.

上一语法中的 type-definition-elements-and-members 表示成员声明和定义。 结构可以具有构造函数和可变字段和不可变字段,并且可以声明成员和接口实现。 有关详细信息,请参阅 成员

结构不能参与继承,不能包含 letdo 绑定,并且不能以递归方式包含其自己的类型的字段(尽管它们可以包含引用其自己的类型的引用单元格)。

由于结构不允许 let 绑定,因此必须使用关键字声明结构 val 中的字段。 关键字 val 定义字段及其类型,但不允许初始化。 相反, val 声明初始化为零或 null。 因此,具有隐式构造函数(即声明中结构名称后立即给出的参数)的结构要求 val 使用 DefaultValue 特性注释声明。 具有已定义构造函数的结构仍支持零初始化。 因此,该 DefaultValue 属性是一个声明,表明此类零值对字段有效。 结构的隐式构造函数不会执行任何作,因为letdo不允许对类型执行绑定,但传入的隐式构造函数参数值可用作专用字段。

显式构造函数可能涉及字段值的初始化。 如果有具有显式构造函数的结构,它仍支持零初始化;但是,不要对val声明使用DefaultValue特性,因为它与显式构造函数冲突。 有关声明的详细信息 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 refC# 。

在只读结构中定义可变值会产生错误。

结构记录和歧视联合

可以使用属性将 记录歧视联合 表示为结构 [<Struct>] 。 请参阅每篇文章了解详细信息。

另请参阅