Structuren
Een structuur is een compact objecttype dat efficiënter kan zijn dan een klasse voor typen met een kleine hoeveelheid gegevens en eenvoudig gedrag.
Syntaxis
[ 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
Opmerkingen
Structuren zijn waardetypen, wat betekent dat ze rechtstreeks op de stapel worden opgeslagen of, wanneer ze worden gebruikt als velden of matrixelementen, inline in het bovenliggende type. In tegenstelling tot klassen en records hebben structuren semantiek van pass-by-value. Dit betekent dat ze voornamelijk nuttig zijn voor kleine aggregaties van gegevens die regelmatig worden geopend en gekopieerd.
In de vorige syntaxis worden twee formulieren weergegeven. De eerste is niet de lichtgewicht syntaxis, maar wordt echter vaak gebruikt, omdat u, wanneer u de struct
en end
trefwoorden gebruikt, het StructAttribute
kenmerk weglaat, dat in het tweede formulier wordt weergegeven. Je kunt afkoren StructAttribute
tot alleen Struct
.
De typedefinitie-elementen en leden in de vorige syntaxis vertegenwoordigen liddeclaraties en definities. Structuren kunnen constructors en onveranderbare en onveranderbare velden hebben, en ze kunnen leden en interface-implementaties declareren. Zie Leden voor meer informatie.
Structuren kunnen niet deelnemen aan overname, kunnen geen bindingen bevatten let
en do
kunnen geen recursief velden van hun eigen type bevatten (hoewel ze verwijzingscellen kunnen bevatten die naar hun eigen type verwijzen).
Omdat structuren geen bindingen toestaan let
, moet u velden in structuren declareren met behulp van het val
trefwoord. Het val
trefwoord definieert een veld en het bijbehorende type, maar staat initialisatie niet toe. In plaats daarvan val
worden declaraties geïnitialiseerd tot nul of null. Daarom vereisen structuren met een impliciete constructor (dat wil gezegd, parameters die direct na de structuurnaam in de declaratie worden gegeven) dat val
declaraties worden geannoteerd met het DefaultValue
kenmerk. Structuren met een gedefinieerde constructor ondersteunen nog steeds nul-initialisatie. Daarom is het DefaultValue
kenmerk een declaratie dat een dergelijke nulwaarde geldig is voor het veld. Impliciete constructors voor structuren voeren geen acties uit omdat let
bindingen do
niet zijn toegestaan voor het type, maar de doorgegeven impliciete constructorparameterwaarden zijn beschikbaar als privévelden.
Expliciete constructors kunnen betrekking hebben op initialisatie van veldwaarden. Wanneer u een structuur hebt met een expliciete constructor, ondersteunt deze nog steeds nul-initialisatie; U gebruikt echter niet het DefaultValue
kenmerk voor de val
declaraties omdat het conflicteert met de expliciete constructor. Zie Expliciete velden: Het val
trefwoord voor meer informatie over val
declaraties.
Kenmerken en toegankelijkheidsaanpassingen zijn toegestaan op structuren en volgen dezelfde regels als die voor andere typen. Zie Kenmerken en toegangsbeheer voor meer informatie.
De volgende codevoorbeelden illustreren structuurdefinities.
// 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
DoorRefLike structs
U kunt uw eigen structs definiëren die voldoen aan byref
-achtige semantiek: zie Byrefs voor meer informatie. Dit gebeurt met het IsByRefLikeAttribute kenmerk:
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
impliceert Struct
niet . Beide moeten aanwezig zijn op het type.
Een 'byref
-like'-struct in F# is een type stack-gebonden waarde. Het wordt nooit toegewezen aan de beheerde heap. Een byref
-achtige struct is handig voor programmeren met hoge prestaties, omdat deze wordt afgedwongen met een set sterke controles over de levensduur en niet-vastleggen. De regels zijn:
- Ze kunnen worden gebruikt als functieparameters, methodeparameters, lokale variabelen, methode retourneert.
- Ze kunnen geen statische of instantieleden van een klasse of normale struct zijn.
- Ze kunnen niet worden vastgelegd door een sluitingsconstructie (
async
methoden of lambda-expressies). - Ze kunnen niet worden gebruikt als een algemene parameter.
Hoewel deze regels het gebruik zeer sterk beperken, doen ze dit om te voldoen aan de belofte van high-performance computing op een veilige manier.
ReadOnly-structs
U kunt aantekeningen toevoegen aan structs met het IsReadOnlyAttribute kenmerk. Voorbeeld:
[<IsReadOnly; Struct>]
type S(count1: int, count2: int) =
member x.Count1 = count1
member x.Count2 = count2
IsReadOnly
impliceert Struct
niet . U moet beide toevoegen om een IsReadOnly
struct te hebben.
Het gebruik van dit kenmerk verzendt metagegevens die F# en C# laten weten om deze te behandelen als inref<'T>
respectievelijk.in ref
Het definiëren van een veranderlijke waarde in een leesbare struct produceert een fout.
Struct Records en Gediscrimineerde Unies
U kunt records en gediscrimineerde unions vertegenwoordigenals structs met het [<Struct>]
kenmerk. Zie elk artikel voor meer informatie.