Anonieme records
Anonieme records zijn eenvoudige aggregaties van benoemde waarden die niet hoeven te worden gedeclareerd voor gebruik. U kunt ze declareren als structs of verwijzingstypen. Dit zijn standaard referentietypen.
Syntaxis
In de volgende voorbeelden ziet u de syntaxis van anonieme records. Items die zijn gescheiden als [item]
optioneel.
// 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; ...|}) ...
Basaal gebruik
Anonieme records kunnen het beste worden beschouwd als F#-recordtypen die niet hoeven te worden gedeclareerd voordat er een instantie wordt geïnstantieerd.
Hier ziet u bijvoorbeeld hoe u kunt communiceren met een functie die een anonieme record produceert:
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
In het volgende voorbeeld wordt de vorige uitgebreid met een printCircleStats
functie die een anonieme record als invoer gebruikt:
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
Bellen printCircleStats
met een anoniem recordtype dat niet dezelfde shape heeft als het invoertype, kan niet worden gecompileerd:
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"]'
Anonieme Struct-records
Anonieme records kunnen ook worden gedefinieerd als struct met het optionele struct
trefwoord. In het volgende voorbeeld wordt het vorige voorbeeld vergroot door een anonieme structrecord te produceren en te gebruiken:
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
Structness-deductie
Anonieme struct-records maken ook 'structness-deductie' mogelijk, waarbij u het struct
trefwoord niet hoeft op te geven op de oproepsite. In dit voorbeeld gebruikt u het trefwoord bij het struct
aanroepen printCircleStats
:
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 |}
Het omgekeerde patroon - opgeven struct
wanneer het invoertype geen anonieme struct-record is - kan niet worden gecompileerd.
Anonieme records insluiten binnen andere typen
Het is handig om gediscrimineerde vakbonden te declareren waarvan de zaken records zijn. Maar als de gegevens in de records hetzelfde type zijn als de gediscrimineerde samenvoeging, moet u alle typen definiëren als wederzijds recursief. Het gebruik van anonieme records voorkomt deze beperking. Wat volgt is een voorbeeldtype en functie die het patroon ermee overeenkomt:
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
Expressies kopiëren en bijwerken
Anonieme records ondersteunen constructie met kopieer- en update-expressies. U kunt bijvoorbeeld als volgt een nieuw exemplaar van een anonieme record maken waarmee een bestaande gegevens worden gekopieerd:
let data = {| X = 1; Y = 2 |}
let data' = {| data with Y = 3 |}
In tegenstelling tot benoemde records kunt u met anonieme records echter volledig verschillende formulieren maken met kopieer- en update-expressies. In het volgende voorbeeld wordt dezelfde anonieme record uit het vorige voorbeeld gebruikt en uitgebreid naar een nieuwe anonieme record:
let data = {| X = 1; Y = 2 |}
let expandedData = {| data with Z = 3 |} // Gives {| X=1; Y=2; Z=3 |}
Het is ook mogelijk om anonieme records te maken van exemplaren van benoemde records:
type R = { X: int }
let data = { X = 1 }
let data' = {| data with Y = 2 |} // Gives {| X=1; Y=2 |}
U kunt ook gegevens kopiëren naar en van verwijzingen naar en struct anonieme records:
// 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 |}
Eigenschappen van anonieme records
Anonieme records hebben een aantal kenmerken die essentieel zijn om volledig te begrijpen hoe ze kunnen worden gebruikt.
Anonieme records zijn nominaal
Anonieme records zijn nominale typen. Ze worden het beste beschouwd als benoemde recordtypen (die ook nominaal zijn) waarvoor geen declaratie vooraf is vereist.
Bekijk het volgende voorbeeld met twee anonieme recorddeclaraties:
let x = {| X = 1 |}
let y = {| Y = 1 |}
De x
waarden hebben y
verschillende typen en zijn niet compatibel met elkaar. Ze zijn niet gelijkbaar en ze zijn niet vergelijkbaar. U kunt dit illustreren door een benoemd recordequivalent te overwegen:
type X = { X: int }
type Y = { Y: int }
let x = { X = 1 }
let y = { Y = 1 }
Er is niets inherent anders over anonieme records in vergelijking met hun benoemde record-equivalenten wanneer het gaat om gelijkwaardigheid of vergelijking van het type.
Anonieme records maken gebruik van structurele gelijkheid en vergelijking
Net als bij recordtypen zijn anonieme records structureel gelijkbaar en vergelijkbaar. Dit geldt alleen als alle samenstellende typen gelijkheid en vergelijking ondersteunen, zoals bij recordtypen. Om gelijkheid of vergelijking te ondersteunen, moeten twee anonieme records dezelfde 'shape' hebben.
{| 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|}
Anonieme records kunnen worden geserialiseerbaar
U kunt anonieme records net zo serialiseren als met benoemde records. Hier volgt een voorbeeld met 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}"
Anonieme records zijn handig voor het verzenden van lichtgewicht gegevens via een netwerk zonder dat u vooraf een domein hoeft te definiëren voor uw geserialiseerde/gedeserialiseerde typen.
Anonieme records werken samen met anonieme C#-typen
Het is mogelijk om een .NET API te gebruiken waarvoor het gebruik van anonieme C#-typen is vereist. Anonieme C#-typen zijn triviaal om mee te werken met behulp van anonieme records. In het volgende voorbeeld ziet u hoe u anonieme records gebruikt om een LINQ-overbelasting aan te roepen waarvoor een anoniem type is vereist:
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}"
Er zijn een groot aantal andere API's die worden gebruikt in .NET waarvoor het gebruik van het doorgeven van een anoniem type is vereist. Anonieme records zijn uw hulpprogramma voor het werken met hen.
Beperkingen
Anonieme records hebben enkele beperkingen in hun gebruik. Sommige zijn inherent aan hun ontwerp, maar andere kunnen worden gewijzigd.
Beperkingen met patroonkoppeling
Anonieme records bieden geen ondersteuning voor patroonkoppeling, in tegenstelling tot benoemde records. Er zijn drie redenen:
- Een patroon moet rekening houden met elk veld van een anonieme record, in tegenstelling tot benoemde recordtypen. Dit komt doordat anonieme records geen ondersteuning bieden voor structurele subtypen. Dit zijn nominale typen.
- Vanwege (1) is er geen mogelijkheid om extra patronen in een patroonovereenkomstexpressie te hebben, omdat elk afzonderlijk patroon een ander anoniem recordtype zou impliceren.
- Vanwege (2) zou elk anoniem recordpatroon uitgebreider zijn dan het gebruik van 'punt'-notatie.
Er is een open taalsuggesties om patroonkoppeling in beperkte contexten toe te staan.
Beperkingen met de mutabiliteit
Het is momenteel niet mogelijk om een anonieme record met mutable
gegevens te definiëren. Er is een open taalsuggesties om veranderlijke gegevens toe te staan.
Beperkingen met anonieme structrecords
Het is niet mogelijk om anonieme records te declareren als IsByRefLike
of IsReadOnly
. Er is een open taalsuggesties voor IsByRefLike
en IsReadOnly
anonieme records.