Partager via


Enregistrements (F#)

Les enregistrements représentent des agrégats simples de valeurs nommées, éventuellement avec des membres.

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

Notes

Dans la syntaxe précédente, typename est le nom du type d'enregistrement, label1 et label2 sont des noms de valeurs, ou étiquettes, et type1 et type2 sont les types de ces valeurs.member-list est la liste facultative de membres pour le type.

Voici quelques exemples.

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

Lorsque chaque étiquette se trouve sur une ligne séparée, le point-virgule est facultatif.

Vous pouvez définir des valeurs dans les expressions appelées expressions d'enregistrement.Le compilateur déduit le type à partir des étiquettes utilisées (si les étiquettes sont suffisamment distinctes de celles d'autres types d'enregistrement).Les accolades ({}) entourent l'expression d'enregistrement.Le code suivant affiche une expression d'enregistrement qui initialise un enregistrement avec trois éléments flottants portant les étiquettes x, y et z.

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

N'utilisez pas la forme abrégée au cas où un autre type aurait les mêmes étiquettes.

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; }

Les étiquettes du type le plus récemment déclaré ont priorité sur celles du type précédemment déclaré. Donc, dans l'exemple précédent, il est déduit que mypoint3D est Point3D.Vous pouvez spécifier le type d'enregistrement explicitement, comme dans le code suivant.

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

Des méthodes peuvent être définies pour les types d'enregistrement tout comme pour les types de classe.

Création d'enregistrements à l'aide d'expressions d'enregistrement

Vous pouvez initialiser des enregistrements à l'aide des étiquettes définies dans l'enregistrement.Une telle expression est appelée expression d'enregistrement.Utilisez des accolades pour encadrer l'expression d'enregistrement, et le point-virgule comme délimiteur.

L'exemple suivant montre comment créer un enregistrement.

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

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

Les points-virgules après le dernier champ de l'expression d'enregistrement et de la définition de type sont facultatifs, que les champs soient tous sur une ligne ou pas.

Lorsque vous créez un enregistrement, vous devez fournir des valeurs pour chaque champ.Vous ne pouvez pas faire référence aux valeurs d'autres champs dans l'expression d'initialisation d'un champ.

Dans le code suivant, le type de myRecord2 est déduit des noms des champs.Vous pouvez éventuellement spécifier le nom du type de manière explicite.

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

Une autre forme de construction d'enregistrement peut être utile lorsque vous devez copier un enregistrement existant, voire modifier certaines valeurs de champ.La ligne de code suivante illustre ceci.

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

Cette forme d'expression d'enregistrement est appelée expression d'enregistrement de copie et de mise à jour.

Les enregistrements sont immuables par défaut ; toutefois, vous pouvez facilement créer des enregistrements modifiés à l'aide d'une copie et d'une expression de mise à jour.Vous pouvez également spécifier explicitement un champ mutable.

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

N'utilisez pas l'attribut DefaultValue avec des champs de l'enregistrement.Une meilleure approche consiste à définir des instances par défaut des enregistrements avec des champs qui sont initialisés avec les valeurs par défaut puis d'utiliser une expression d'enregistrement de copie et de mise à jour pour définir tous les champs qui diffèrent des valeurs par défaut.

// Rather than use [<DefaultValue>], define a default record.
type MyRecord =
    { 
        field1 : int 
        field2 : int
    }

let defaultRecord1 = { field1 = 0; field2 = 0 }
let defaultRecord2 = { field1 = 1; field2 = 25 }

// Use the with keyword to populate only a few chosen fields
// and leave the rest with default values.
let rr3 = { defaultRecord1 with field2 = 42 }

Critères spéciaux avec enregistrements

Les enregistrements peuvent être utilisés avec les critères spéciaux.Vous pouvez spécifier des champs explicitement et fournir des variables pour d'autres champs qui seront assignées lorsqu'une correspondance se produira.L'exemple de code suivant illustre ceci.

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 }

La sortie de ce code est la suivante.

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

Différences entre enregistrements et classes

Les champs d'enregistrement diffèrent des classes en ce qu'ils sont automatiquement exposés en tant que propriétés, et sont utilisés dans le cadre de la création et de la copie d'enregistrements.La construction d'enregistrement diffère également de la construction de classe.Dans un type d'enregistrement, vous ne pouvez pas définir de constructeur.Au lieu de cela, la syntaxe de construction décrite dans cette rubrique s'applique.Les classes n'ont aucune relation directe entre les paramètres du constructeur, les champs et les propriétés.

Comme les types d'union et de structure, les enregistrements ont une sémantique d'égalité structurelle.Les classes ont une sémantique d'égalité de référence.L'exemple de code suivant illustre ceci.

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."

Si vous écriviez le même code avec des classes, les deux objets de classe seraient inégaux parce que les deux valeurs représenteraient deux objets sur le tas et seules les adresses seraient comparées (à moins que le type de classe ne remplace la méthode System.Object.Equals).

Voir aussi

Référence

Classes (F#)

Critères spéciaux (F#)

Autres ressources

Types F#

Référence du langage F#