結構

「結構」是一種精簡的物件類型,比起有少量資料和簡單行為的類型類別更有效率。

語法

[ 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 繫結,但傳入的隱含建構函式參數值均可用作為私用欄位。

明確建構函式可能會牽涉到欄位值的初始化。 當您的結構有明確的建構函式時,它仍然可以支援零初始化。不過,請勿在 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 運算式) 擷取。
  • 不能作為泛型參數。

雖然這些規則強烈限制了使用方式,但這是為了保證能夠以安全的方式進行高效能運算。

唯讀結構

您可以使用 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

在唯讀結構內定義可變值會產生錯誤。

結構記錄和差別聯集

您可以使用 [<Struct>] 屬性,將記錄差別聯集表示為結構。 請參閱每篇文章以深入了解。

另請參閱