Struktury

Struktura to kompaktowy typ obiektu, który może być bardziej wydajny niż klasa dla typów, które mają niewielką ilość danych i proste zachowanie.

Składnia

[ 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

Uwagi

Struktury to typy wartości, co oznacza, że są przechowywane bezpośrednio na stosie lub, gdy są używane jako pola lub elementy tablicy, wbudowane w typ nadrzędny. W przeciwieństwie do klas i rekordów struktury mają semantyka typu pass-by-value. Oznacza to, że są one przydatne głównie w przypadku małych agregacji danych, które są często używane i kopiowane.

W poprzedniej składni są wyświetlane dwa formularze. Pierwszy nie jest lekką składnią, ale jest jednak często używany, ponieważ w przypadku użycia struct słów kluczowych i end można pominąć StructAttribute atrybut, który pojawia się w drugim formularzu. Można skrócić StructAttribute do tylko Struct.

W poprzedniej składni type-definition-elements-and-members reprezentuje deklaracje i definicje składowych. Struktury mogą mieć konstruktory i modyfikowalne i niezmienne pola, a także mogą deklarować implementacje elementów członkowskich i interfejsu. Aby uzyskać więcej informacji, zobacz Członkowie.

Struktury nie mogą uczestniczyć w dziedziczeniu, nie mogą zawierać let ani do wiązać ani nie mogą rekursywnie zawierać pól własnego typu (chociaż mogą zawierać komórki referencyjne odwołujące się do własnego typu).

Ponieważ struktury nie zezwalają na let powiązania, należy zadeklarować pola w strukturach przy użyciu słowa kluczowego val . Słowo val kluczowe definiuje pole i jego typ, ale nie zezwala na inicjowanie. val Zamiast tego deklaracje są inicjowane na zero lub null. Z tego powodu struktury, które mają niejawny konstruktor (czyli parametry podane bezpośrednio po nazwie struktury w deklaracji), wymagają, aby val deklaracje zostały oznaczone za pomocą atrybutu DefaultValue . Struktury, które mają zdefiniowany konstruktor, nadal obsługują inicjowanie zerowe. W związku z tym atrybut jest deklaracją, DefaultValue że taka wartość zero jest prawidłowa dla pola. Niejawne konstruktory struktur nie wykonują żadnych akcji, ponieważ let powiązania i do nie są dozwolone w typie, ale niejawne wartości parametrów konstruktora przekazane w pliku są dostępne jako pola prywatne.

Jawne konstruktory mogą obejmować inicjowanie wartości pól. Jeśli masz strukturę, która ma jawny konstruktor, nadal obsługuje inicjowanie zerowe; nie należy jednak używać atrybutu DefaultValueval w deklaracjach, ponieważ powoduje konflikt z jawnym konstruktorem. Aby uzyskać więcej informacji na temat val deklaracji, zobacz Jawne pola: val Słowo kluczowe.

Atrybuty i modyfikatory ułatwień dostępu są dozwolone w strukturach i są zgodne z tymi samymi regułami co w przypadku innych typów. Aby uzyskać więcej informacji, zobacz Atrybuty i kontrola dostępu.

Poniższe przykłady kodu ilustrują definicje struktury.

// 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, struktury

Aby uzyskać więcej informacji, możesz zdefiniować własne struktury, które mogą być zgodne z byrefsemantykami przypominającymi semantykę: zobacz Byrefs . Odbywa się to za pomocą atrybutu 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 nie oznacza Struct. Oba muszą być obecne w typie.

Struktura "byref-like" w języku F# jest typem wartości powiązanej ze stosem. Nigdy nie jest przydzielany na zarządzanym stercie. Struktura podobna byrefdo typu jest przydatna w przypadku programowania o wysokiej wydajności, ponieważ jest wymuszana przy użyciu zestawu silnych testów dotyczących okresu istnienia i nieuchwytywania. Reguły to:

  • Można ich używać jako parametrów funkcji, parametrów metody, zmiennych lokalnych, zwracanych metod.
  • Nie mogą być statyczne lub wystąpienia składowe klasy ani struktury normalnej.
  • Nie można ich przechwycić za pomocą żadnej konstrukcji zamknięcia (async metod ani wyrażeń lambda).
  • Nie można ich używać jako parametru ogólnego.

Chociaż te reguły bardzo mocno ograniczają użycie, robią to, aby spełnić obietnicę obliczeń o wysokiej wydajności w bezpieczny sposób.

ReadOnly, struktury

Możesz dodawać adnotacje do struktur za pomocą atrybutu IsReadOnlyAttribute . Na przykład:

[<IsReadOnly; Struct>]
type S(count1: int, count2: int) =
    member x.Count1 = count1
    member x.Count2 = count2

IsReadOnly nie oznacza Struct. Aby mieć IsReadOnly strukturę, należy dodać obie.

Użycie tego atrybutu emituje metadane, dzięki czemu język F# i C# wiedzą, aby traktować go odpowiednio jako inref<'T> i in ref.

Zdefiniowanie wartości modyfikowalnej wewnątrz struktury readonly powoduje błąd.

Rekordy struktury i związki dyskryminujące

Rekordy i związki dyskryminujące można reprezentować jako struktury z atrybutem [<Struct>] . Zobacz każdy artykuł, aby dowiedzieć się więcej.

Zobacz też