Note
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de changer d’annuaire.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de changer d’annuaire.
Les enregistrements anonymes sont des agrégats simples de valeurs nommées qui n’ont pas besoin d’être déclarées avant l’utilisation. Vous pouvez les déclarer en tant que structs ou types référence. Ils sont des types de référence par défaut.
Syntaxe
Les exemples suivants illustrent la syntaxe d’enregistrement anonyme. Éléments délimités comme [item] facultatifs.
// Construct an anonymous record
let value-name = [struct] {| Label1: Type1; Label2: Type2; ...|}
// Use an anonymous record as a type parameter
let value-name = Type-Name<[struct] {| Label1: Type1; Label2: Type2; ...|}>
// Define a parameter with an anonymous record as input
let function-name (arg-name: [struct] {| Label1: Type1; Label2: Type2; ...|}) ...
Utilisation de base
Les enregistrements anonymes sont considérés comme des types d’enregistrements F# qui n’ont pas besoin d’être déclarés avant l’instanciation.
Par exemple, voici comment interagir avec une fonction qui produit un enregistrement anonyme :
open System
let getCircleStats radius =
let d = radius * 2.0
let a = Math.PI * (radius ** 2.0)
let c = 2.0 * Math.PI * radius
{| Diameter = d; Area = a; Circumference = c |}
let r = 2.0
let stats = getCircleStats r
printfn "Circle with radius: %f has diameter %f, area %f, and circumference %f"
r stats.Diameter stats.Area stats.Circumference
L’exemple suivant se développe sur le précédent avec une printCircleStats fonction qui accepte un enregistrement anonyme comme entrée :
open System
let getCircleStats radius =
let d = radius * 2.0
let a = Math.PI * (radius ** 2.0)
let c = 2.0 * Math.PI * radius
{| Diameter = d; Area = a; Circumference = c |}
let printCircleStats r (stats: {| Area: float; Circumference: float; Diameter: float |}) =
printfn "Circle with radius: %f has diameter %f, area %f, and circumference %f"
r stats.Diameter stats.Area stats.Circumference
let r = 2.0
let stats = getCircleStats r
printCircleStats r stats
L’appel printCircleStats avec n’importe quel type d’enregistrement anonyme qui n’a pas la même « forme » que le type d’entrée ne parvient pas à compiler :
printCircleStats r {| Diameter = 2.0; Area = 4.0; MyCircumference = 12.566371 |}
// Two anonymous record types have mismatched sets of field names
// '["Area"; "Circumference"; "Diameter"]' and '["Area"; "Diameter"; "MyCircumference"]'
Struct des enregistrements anonymes
Les enregistrements anonymes peuvent également être définis comme struct avec le mot clé facultatif struct . L’exemple suivant augmente le précédent en produisant et en consommant un enregistrement anonyme de struct :
open System
let getCircleStats radius =
let d = radius * 2.0
let a = Math.PI * (radius ** 2.0)
let c = 2.0 * Math.PI * radius
// Note that the keyword comes before the '{| |}' brace pair
struct {| Area = a; Circumference = c; Diameter = d |}
// the 'struct' keyword also comes before the '{| |}' brace pair when declaring the parameter type
let printCircleStats r (stats: struct {| Area: float; Circumference: float; Diameter: float |}) =
printfn "Circle with radius: %f has diameter %f, area %f, and circumference %f"
r stats.Diameter stats.Area stats.Circumference
let r = 2.0
let stats = getCircleStats r
printCircleStats r stats
Inférence de structivité
Les enregistrements anonymes de struct autorisent également l'« inférence de structness » où vous n’avez pas besoin de spécifier le struct mot clé sur le site d’appel. Dans cet exemple, vous allez éliser le mot clé lors de l’appel structprintCircleStats:
let printCircleStats r (stats: struct {| Area: float; Circumference: float; Diameter: float |}) =
printfn "Circle with radius: %f has diameter %f, area %f, and circumference %f"
r stats.Diameter stats.Area stats.Circumference
printCircleStats r {| Area = 4.0; Circumference = 12.6; Diameter = 12.6 |}
Le modèle inverse , en spécifiant struct quand le type d’entrée n’est pas un enregistrement anonyme de struct, ne peut pas être compilé.
Incorporation d’enregistrements anonymes dans d’autres types
Il est utile de déclarer des syndicats discriminatoires dont les cas sont enregistrés . Toutefois, si les données des enregistrements sont du même type que l’union discriminée, vous devez définir tous les types comme récursifs mutuellement. L’utilisation d’enregistrements anonymes évite cette restriction. Voici un exemple de type et de fonction qui correspondent à celui-ci :
type FullName = { FirstName: string; LastName: string }
// Note that using a named record for Manager and Executive would require mutually recursive definitions.
type Employee =
| Engineer of FullName
| Manager of {| Name: FullName; Reports: Employee list |}
| Executive of {| Name: FullName; Reports: Employee list; Assistant: Employee |}
let getFirstName e =
match e with
| Engineer fullName -> fullName.FirstName
| Manager m -> m.Name.FirstName
| Executive ex -> ex.Name.FirstName
Copier et mettre à jour des expressions
Les enregistrements anonymes prennent en charge la construction avec des expressions de copie et de mise à jour. Par exemple, voici comment construire une nouvelle instance d’un enregistrement anonyme qui copie les données d’un enregistrement existant :
let data = {| X = 1; Y = 2 |}
let data' = {| data with Y = 3 |}
Toutefois, contrairement aux enregistrements nommés, les enregistrements anonymes vous permettent de construire des formulaires entièrement différents avec des expressions de copie et de mise à jour. L’exemple suivant prend le même enregistrement anonyme de l’exemple précédent et le développe dans un nouvel enregistrement anonyme :
let data = {| X = 1; Y = 2 |}
let expandedData = {| data with Z = 3 |} // Gives {| X=1; Y=2; Z=3 |}
Il est également possible de construire des enregistrements anonymes à partir d’instances d’enregistrements nommés :
type R = { X: int }
let data = { X = 1 }
let data' = {| data with Y = 2 |} // Gives {| X=1; Y=2 |}
Vous pouvez également copier des données vers et depuis des enregistrements anonymes de référence et de struct :
// Copy data from a reference record into a struct anonymous record
type R1 = { X: int }
let r1 = { X = 1 }
let data1 = struct {| r1 with Y = 1 |}
// Copy data from a struct record into a reference anonymous record
[<Struct>]
type R2 = { X: int }
let r2 = { X = 1 }
let data2 = {| r1 with Y = 1 |}
// Copy the reference anonymous record data into a struct anonymous record
let data3 = struct {| data2 with Z = r2.X |}
Propriétés des enregistrements anonymes
Les enregistrements anonymes ont un certain nombre de caractéristiques essentielles pour comprendre pleinement comment ils peuvent être utilisés.
Les enregistrements anonymes utilisent l’égalité structurelle et la comparaison
Comme les types d’enregistrements, les enregistrements anonymes sont structurellement comparables et comparables. Cela n’est vrai que si tous les types constituants prennent en charge l’égalité et la comparaison, comme avec les types d’enregistrements. Pour prendre en charge l’égalité ou la comparaison, deux enregistrements anonymes doivent avoir la même « forme ».
{| a = 1+1 |} = {| a = 2 |} // true
{| a = 1+1 |} > {| a = 1 |} // true
// error FS0001: Two anonymous record types have mismatched sets of field names '["a"]' and '["a"; "b"]'
{| a = 1 + 1 |} = {| a = 2; b = 1|}
Les enregistrements anonymes sont sérialisables
Vous pouvez sérialiser des enregistrements anonymes comme vous le pouvez avec des enregistrements nommés. Voici un exemple utilisant Newtonsoft.Json :
open Newtonsoft.Json
let phillip' = {| name="Phillip"; age=28 |}
let philStr = JsonConvert.SerializeObject(phillip')
let phillip = JsonConvert.DeserializeObject<{|name: string; age: int|}>(philStr)
printfn $"Name: {phillip.name} Age: %d{phillip.age}"
Les enregistrements anonymes sont utiles pour envoyer des données légères sur un réseau sans avoir à définir un domaine pour vos types sérialisés/désérialisés à l’avant.
Enregistrements anonymes interopérables avec des types anonymes C#
Il est possible d’utiliser une API .NET qui nécessite l’utilisation de types anonymes C#. Les types anonymes C# sont trivials pour interagir avec à l’aide d’enregistrements anonymes. L’exemple suivant montre comment utiliser des enregistrements anonymes pour appeler une surcharge LINQ qui nécessite un type anonyme :
open System.Linq
let names = [ "Ana"; "Felipe"; "Emilia"]
let nameGrouping = names.Select(fun n -> {| Name = n; FirstLetter = n[0] |})
for ng in nameGrouping do
printfn $"{ng.Name} has first letter {ng.FirstLetter}"
Il existe une multitude d’autres API utilisées dans .NET qui nécessitent l’utilisation de la transmission d’un type anonyme. Les enregistrements anonymes sont votre outil pour les utiliser.
Limites
Les enregistrements anonymes ont certaines restrictions dans leur utilisation. Certains sont inhérents à leur conception, mais d’autres sont amenables à changer.
Limitations avec la mise en correspondance des modèles
Les enregistrements anonymes ne prennent pas en charge la correspondance des modèles, contrairement aux enregistrements nommés. Il existe trois raisons :
- Un modèle doit tenir compte de chaque champ d’un enregistrement anonyme, contrairement aux types d’enregistrements nommés. Cela est dû au fait que les enregistrements anonymes ne prennent pas en charge les sous-types structurels : ils nécessitent une correspondance exacte des champs.
- En raison de (1), il n’existe aucune possibilité d’avoir des modèles supplémentaires dans une expression de correspondance de modèle, car chaque modèle distinct implique un type d’enregistrement anonyme différent.
- En raison de (2), tout modèle d’enregistrement anonyme serait plus détaillé que l’utilisation de la notation « dot ».
Il existe une suggestion de langage ouverte pour autoriser la correspondance des modèles dans des contextes limités.
Limitations de la mutabilité
Il n’est actuellement pas possible de définir un enregistrement anonyme avec mutable des données. Il existe une suggestion de langage ouverte pour autoriser les données mutables.
Limitations avec les enregistrements anonymes de struct
Il n’est pas possible de déclarer des enregistrements anonymes sous IsByRefLike ou IsReadOnly. Il existe une suggestion de langue ouverte pour les enregistrements anonymes et IsByRefLike pour IsReadOnly les enregistrements.