結構
「結構」是一種精簡的物件類型,比起有少量資料和簡單行為的類型類別更有效率。
語法
[ 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-elements-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 運算式) 擷取。 - 不能作為泛型參數。
雖然這些規則強烈限制了使用方式,但這是為了保證能夠以安全的方式進行高效能運算。
唯讀結構
您可以使用 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>]
屬性,將記錄和差別聯集表示為結構。 請參閱每篇文章以深入了解。