Strukturen
Eine Struktur ist ein kompakter Objekttyp, der für Typen, die nur eine geringe Datenmenge und ein einfaches Verhalten aufweisen, effizienter als eine Klasse sein kann.
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
Bemerkungen
Strukturen sind Werttypen, d. h., sie werden direkt im Stapel oder, wenn sie als Felder oder Array-Elemente verwendet werden, inline im übergeordneten Typ gespeichert. Im Gegensatz zu Klassen und Datensätzen verfügen Strukturen über eine Übergabewertsemantik. Dies bedeutet, dass sie hauptsächlich für kleine Datenaggregate sinnvoll sind, die häufig aufgerufen und kopiert werden.
In der vorherigen Syntax werden zwei Formen gezeigt. Die erste ist nicht die einfache Syntax, aber sie wird trotzdem häufig verwendet, da Sie bei Verwendung der Schlüsselwörter struct
und end
das StructAttribute
-Attribut auslassen können, das in der zweiten Form angezeigt wird. Sie können StructAttribute
zu Struct
abkürzen.
Die Zeile type-definition-elements-and-members in der obigen Syntax steht für Memberdeklarationen und -definitionen. Strukturen können über Konstruktoren sowie änderbare und unveränderliche Felder verfügen, und sie können Member und Schnittstellenimplementierungen deklarieren. Weitere Informationen finden Sie unter Member.
Strukturen können nicht an der Vererbung beteiligt sein, sie können keine let
- oder do
-Bindungen enthalten und können nicht rekursiv Felder des eigenen Typs enthalten (obwohl sie Verweiszellen enthalten können, die auf den eigenen Typ verweisen).
Da Strukturen keine let
-Bindungen zulassen, müssen Sie Felder in Strukturen mit dem val
-Schlüsselwort deklarieren. Das val
-Schlüsselwort definiert ein Feld und den Typ, es lässt jedoch keine Initialisierung zu. In diesem Fall werden val
-Deklarationen mit 0 oder null initialisiert. Aus diesem Grund erfordern Strukturen, die über einen impliziten Konstruktor verfügen (d. h. Parameter, die direkt nach dem Strukturnamen in der Deklaration angegeben werden), dass val
-Deklarationen mit dem DefaultValue
-Attribut gekennzeichnet werden. Strukturen, die über einen definierten Konstruktor verfügen, unterstützen weiterhin die Initialisierung mit 0 (null). Aus diesem Grund ist das DefaultValue
-Attribut eine Deklaration, dass der Wert 0 (Null) für das Feld gültig ist. Implizite Konstruktoren für Strukturen führen keine Aktionen aus, da let
- und do
-Bindungen für den Typ nicht zulässig sind, aber die übergebenen impliziten Konstruktorparameterwerte sind als private Felder verfügbar.
Explizite Konstruktoren können eine Initialisierung von Feldwerten beinhalten. Wenn Sie eine Struktur mit einem expliziten Konstruktor haben, unterstützt sie weiterhin die Initialisierung mit 0 (Null); Sie verwenden jedoch nicht das DefaultValue
-Attribut auf den val
-Deklarationen, da es mit dem expliziten Konstruktor in Konflikt steht. Weitere Informationen zu val
-Deklarationen finden Sie unter Explizite Felder: Das val
-Schlüsselwort.
Attribute und Zugriffsmodifizierer sind für Strukturen zulässig und folgen denselben Regeln wie jene für andere Typen. Weitere Informationen finden Sie unter Attribute und Zugriffssteuerung.
Die folgenden Codebeispiele veranschaulichen Strukturdefinitionen.
// 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-Strukturen
Sie können eigene Strukturen definieren, die eine Semantik ähnlich byref
einhalten können. Weitere Informationen finden Sie unter Byrefs. Verwenden Sie dazu das IsByRefLikeAttribute-Attribut:
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
impliziert nicht Struct
. Beides muss im Typ vorhanden sein.
Eine byref
-ähnliche Struktur in F# ist ein stapelgebundener Werttyp. Sie wird niemals für den verwalteten Heap zugeordnet. Eine byref
-ähnliche Struktur ist bei der Hochleistungsprogrammierung hilfreich, da sie mit einer Reihe strenger Überprüfungen der Lebensdauer und der Nichterfassung erzwungen wird. Die Regeln lauten:
- Sie können als Funktionsparameter, Methodenparameter, lokale Variablen und Methodenrückgaben verwendet werden.
- Sie können nicht statisch oder Instanzmember einer Klasse oder normalen Struktur sein.
- Sie können nicht von einem Abschlusskonstrukt (
async
-Methoden oder Lambdaausdrücke) erfasst werden. - Sie können nicht als generischer Parameter verwendet werden.
Diese Regeln schränken die Nutzung zwar sehr stark ein, dies geschieht jedoch, um sicheres Hochleistungscomputing zu ermöglichen.
ReadOnly-Strukturen
Sie können Strukturen mithilfe des Attributs IsReadOnlyAttribute mit Anmerkungen versehen. Zum Beispiel:
[<IsReadOnly; Struct>]
type S(count1: int, count2: int) =
member x.Count1 = count1
member x.Count2 = count2
IsReadOnly
impliziert nicht Struct
. Sie müssen beide hinzufügen, um eine IsReadOnly
-Struktur zu erhalten.
Die Verwendung dieses Attributs gibt Metadaten aus, die F# und C# darüber informieren, dass es als inref<'T>
bzw. in ref
behandelt werden soll.
Das Definieren eines veränderbaren Werts innerhalb einer ReadOnly-Struktur erzeugt einen Fehler.
Strukturdatensätze und diskriminierte Vereinigungen
Sie können Datensätze und diskriminierte Vereinigungen als Struktur mit dem Attribut [<Struct>]
darstellen. Weitere Informationen finden Sie in den einzelnen Artikeln.