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 DefaultValue
val
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 byref
semantykami 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 byref
do 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.