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 structStructAttribute 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 Structinte . 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 Structinte . 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.

Se även