Strukturer
En struktur är en kompakt objekttyp som kan vara effektivare än en klass för typer som har en liten mängd data och enkelt beteende.
Syntax
[ 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
Kommentarer
Strukturer är värdetyper, vilket innebär att de lagras direkt i stacken eller, när de används som fält eller matriselement, infogade i den överordnade typen. Till skillnad från klasser och poster har strukturer pass-by-value-semantik. Det innebär att de främst är användbara för små mängder data som används och kopieras ofta.
I den tidigare syntaxen visas två formulär. Den första är inte den lätta syntaxen, men den används ändå ofta eftersom du kan utelämna attributet när du använder nyckelorden struct
StructAttribute
och end
, som visas i det andra formuläret. Du kan förkorta StructAttribute
till bara Struct
.
Type-definition-elements-and-members i den tidigare syntaxen representerar medlemsdeklarationer och definitioner. Strukturer kan ha konstruktorer och föränderliga och oföränderliga fält, och de kan deklarera medlemmar och gränssnittsimplementeringar. Mer information finns i Medlemmar.
Strukturer kan inte delta i arv, får inte innehålla let
eller do
bindningar och kan inte rekursivt innehålla fält av egen typ (även om de kan innehålla referensceller som refererar till sin egen typ).
Eftersom strukturer inte tillåter let
bindningar måste du deklarera fält i strukturer med hjälp av nyckelordet val
. Nyckelordet val
definierar ett fält och dess typ men tillåter inte initiering. I val
stället initieras deklarationer till noll eller null. Därför kräver strukturer som har en implicit konstruktor (dvs. parametrar som anges omedelbart efter strukturnamnet i deklarationen) att val
deklarationerna kommenteras med DefaultValue
attributet. Strukturer som har en definierad konstruktor stöder fortfarande nollinitiering. Därför DefaultValue
är attributet en deklaration om att ett sådant nollvärde är giltigt för fältet. Implicita konstruktorer för strukturer utför inga åtgärder eftersom let
bindningar do
inte tillåts för typen, men de implicita konstruktorparametervärden som skickas in är tillgängliga som privata fält.
Explicita konstruktorer kan innebära initiering av fältvärden. När du har en struktur som har en explicit konstruktor stöder den fortfarande nollinitiering. Du använder DefaultValue
dock inte attributet för deklarationerna val
eftersom det står i konflikt med den explicita konstruktorn. Mer information om val
deklarationer finns i Explicita fält: Nyckelordetval
.
Attribut och hjälpmedelsmodifierare tillåts i strukturer och följer samma regler som för andra typer. Mer information finns i Attribut och åtkomstkontroll.
Följande kodexempel illustrerar strukturdefinitioner.
// 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-structs
Du kan definiera dina egna structs som kan följa byref
-like semantik: se Byrefs för mer information. Detta görs med attributet 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
innebär Struct
inte . Båda måste finnas på typen.
En "byref
-liknande" struct i F# är en stackbunden värdetyp. Det allokeras aldrig på den hanterade heapen. En byref
-liknande struct är användbar för programmering med höga prestanda, eftersom den tillämpas med en uppsättning starka kontroller om livslängd och icke-avbildning. Reglerna är:
- De kan användas som funktionsparametrar, metodparametrar, lokala variabler, metodreturer.
- De kan inte vara statiska eller instansmedlemmar i en klass eller normal struct.
- De kan inte fångas upp av någon stängningskonstruktion (
async
metoder eller lambda-uttryck). - De kan inte användas som en allmän parameter.
Även om dessa regler mycket starkt begränsar användningen, gör de det för att uppfylla löftet om databehandling med höga prestanda på ett säkert sätt.
ReadOnly structs
Du kan kommentera structs med IsReadOnlyAttribute attributet . Till exempel:
[<IsReadOnly; Struct>]
type S(count1: int, count2: int) =
member x.Count1 = count1
member x.Count2 = count2
IsReadOnly
innebär Struct
inte . Du måste lägga till båda för att ha en IsReadOnly
struct.
Användning av det här attributet genererar metadata som låter F# och C# känna till för att behandla det som inref<'T>
respektive in ref
.
Att definiera ett föränderligt värde inuti en skrivskyddad struct genererar ett fel.
Struct-poster och diskriminerade fackföreningar
Du kan representera poster och diskriminerade fackföreningar som structs med [<Struct>]
attributet . Mer information finns i varje artikel.