Datensätze (F#)

Datensätze stellen einfache Aggregate benannter Werte, optional mit Membern, dar.

[ attributes ]
type [accessibility-modifier] typename = { 
    [ mutable ] label1 : type1;
    [ mutable ] label2 : type2;
    ...
    }
    member-list

Hinweise

In der vorhergehenden Syntax ist typename der Name des Datensatztyps, label1 und label2 sind Namen von Werten (Bezeichnungen), und type1 und type2 sind die Typen dieser Werte. member-list ist die optionale Liste der Member für den Typ.

Im Folgenden finden Sie einige Beispiele.

type Point = { x : float; y: float; z: float; }
type Customer = { First : string; Last: string; SSN: uint32; AccountNumber : uint32; }

Wenn sich jede Bezeichnung in einer eigenen Zeile befindet, ist das Semikolon optional.

Sie können Werte in Ausdrücken festlegen, die als Datensatzausdrücke bezeichnet werden. Der Compiler leitet den Typ von den verwendeten Bezeichnungen ab (wenn sich diese ausreichend von den Bezeichnungen anderer Datensatztypen unterscheiden). Der Datensatzausdruck wird in geschweifte Klammern ({ }) eingeschlossen. Im folgenden Code wird ein Datensatzausdruck veranschaulicht, der einen Datensatz mit drei Gleitkommaelementen initialisiert, deren Bezeichnung x, y und z lautet.

let mypoint = { x = 1.0; y = 1.0; z = -1.0; }

Verwenden Sie nicht die Kurzform, wenn ein anderer Typ vorhanden sein kann, der die gleichen Bezeichnungen aufweist.

type Point = { x : float; y: float; z: float; }
type Point3D = { x: float; y: float; z: float }
// Ambiguity: Point or Point3D?
let mypoint3D = { x = 1.0; y = 1.0; z = 0.0; }

Die Bezeichnungen des zuletzt deklarierten Typs haben Vorrang vor den Bezeichnungen des zuvor deklarierten Typs, deshalb wird im vorhergehenden Beispiel mypoint3D als Point3D abgeleitet. Sie können den Eintragstyp, wie im folgenden Code dargestellt, explizit angeben.

let myPoint1 = { Point.x = 1.0; y = 1.0; z = 0.0; }

Methoden können für Datensatztypen wie für Klassentypen definiert werden.

Erstellen von Datensätzen mit Datensatzausdrücken

Sie können Datensätze mit den im Datensatz definierten Bezeichnungen initialisieren. Der Ausdruck, durch den dies erfolgt, wird als Datensatzausdruck bezeichnet. Schließen Sie den Datensatzausdruck in Klammern ein, und verwenden Sie als Trennzeichen ein Semikolon.

Das folgende Beispiel zeigt, wie Sie einen Datensatz erstellen können.

type MyRecord = {
    X: int;
    Y: int;
    Z: int 
    }

let myRecord1 = { X = 1; Y = 2; Z = 3; }

Die Semikolons nach dem letzten Feld im Datensatzausdruck und in der Typdefinition sind optional, unabhängig davon, ob sich die Felder alle auf einer Zeile befinden.

Wenn Sie einen Datensatz erstellen, müssen Sie für alle Felder Werte angeben. Sie können im Initialisierungsausdruck für ein Feld nicht auf die Werte anderer Felder verweisen.

Im folgenden Code wird der Typ von myRecord2 von den Namen der Felder abgeleitet. Optional können Sie den Typnamen explizit angeben.

let myRecord2 = { MyRecord.X = 1; MyRecord.Y = 2; MyRecord.Z = 3 }

Eine andere Form der Datensatzkonstruktion kann nützlich sein, wenn Sie einen vorhandenen Datensatz kopieren müssen und möglicherweise einige Feldwerte ändern. Dies wird in der folgenden Codezeile veranschaulicht.

let myRecord3 = { myRecord2 with Y = 100; Z = 2 }

Diese Form des Datensatzausdrucks wird als Kopier- und Aktualisierungs-Datensatzausdruck bezeichnet.

Datensätze sind standardmäßig unveränderlich. Sie können jedoch geänderte Datensätze leicht mit einer Kopie und einem Updateausdruck erstellen. Sie können auch explizit ein änderbares Feld angeben.

type Car = {
    Make : string
    Model : string
    mutable Odometer : int
    }
let myCar = { Make = "Fabrikam"; Model = "Coupe"; Odometer = 108112 }
myCar.Odometer <- myCar.Odometer + 21

Mustervergleich mit Datensätzen

Datensätze können mit Mustervergleich verwendet werden. Sie können explizit einige Felder angeben und Variablen für andere Felder bereitstellen, die bei einer Übereinstimmung zugewiesen werden. Dies wird im folgenden Codebeispiel veranschaulicht.

type Point3D = { x: float; y: float; z: float }
let evaluatePoint (point: Point3D) =
    match point with
    | { x = 0.0; y = 0.0; z = 0.0 } -> printfn "Point is at the origin."
    | { x = xVal; y = 0.0; z = 0.0 } -> printfn "Point is on the x-axis. Value is %f." xVal
    | { x = 0.0; y = yVal; z = 0.0 } -> printfn "Point is on the y-axis. Value is %f." yVal
    | { x = 0.0; y = 0.0; z = zVal } -> printfn "Point is on the z-axis. Value is %f." zVal
    | { x = xVal; y = yVal; z = zVal } -> printfn "Point is at (%f, %f, %f)." xVal yVal zVal

evaluatePoint { x = 0.0; y = 0.0; z = 0.0 }
evaluatePoint { x = 100.0; y = 0.0; z = 0.0 }
evaluatePoint { x = 10.0; y = 0.0; z = -1.0 }

Dieser Code generiert die folgende Ausgabe.

Point is at the origin.
Point is on the x-axis. Value is 100.000000.
Point is at (10.000000, 0.000000, -1.000000).

Unterschiede zwischen Datensätzen und Klassen

Datensatzfelder unterscheiden sich von Klassen, da sie automatisch als Eigenschaften verfügbar gemacht und beim Erstellen und Kopieren von Datensätzen verwendet werden. Die Datensatzkonstruktion unterscheidet sich auch von der Klassenkonstruktion. In einem Datensatztyp können Sie keinen Konstruktor definieren. Stattdessen wird die in diesem Thema beschriebene Konstruktionssyntax angewendet. Klassen weisen keine direkte Beziehung zwischen Konstruktorparametern, Feldern und Eigenschaften auf.

Wie Union- und Strukturtypen weisen Datensätze strukturelle Gleichheitssemantik auf. Klassen verfügen über Verweisgleichheitssemantik. Dies wird im folgenden Codebeispiel dargestellt.

type RecordTest = { X: int; Y: int }
let record1 = { X = 1; Y = 2 }
let record2 = { X = 1; Y = 2 }
if (record1 = record2) then
    printfn "The records are equal."
else
    printfn "The records are unequal."

Wenn der gleiche Code mit Klassen geschrieben wird, wären die beiden Klassenobjekte ungleich, da die beiden Werte zwei Objekte auf dem Heap darstellen und nur die Adressen (außer wenn der Klassentyp die System.Object.Equals-Methode überschreibt) verglichen werden würden.

Siehe auch

Referenz

Klassen (F#)

Mustervergleich (F#)

Weitere Ressourcen

F#-Typen

F#-Sprachreferenz

Änderungsprotokoll

Datum

Versionsgeschichte

Grund

Mai 2010

Einige Codebeispiele wurden verbessert.

Informationsergänzung.