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 Structniet . 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 Structniet . 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.

Zie ook