Anonyma poster
Anonyma poster är enkla aggregeringar av namngivna värden som inte behöver deklareras före användning. Du kan deklarera dem som antingen structs eller referenstyper. De är referenstyper som standard.
Syntax
I följande exempel visas syntaxen för anonyma poster. Objekt avgränsade som [item]
är valfria.
// 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; ...|}) ...
Grundläggande användning
Anonyma poster betraktas bäst som F#-posttyper som inte behöver deklareras före instansieringen.
Här kan du till exempel interagera med en funktion som skapar en anonym post:
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
I följande exempel expanderas den föregående med en printCircleStats
funktion som tar en anonym post som indata:
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
Det printCircleStats
går inte att kompilera med någon anonym posttyp som inte har samma "form" som indatatypen:
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 anonyma poster
Anonyma poster kan också definieras som struct med det valfria struct
nyckelordet. I följande exempel utökas den föregående genom att en struct anonym post skapas och förbrukas:
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-slutsatsdragning
Struct anonyma poster tillåter också "structness-slutsatsdragning" där du inte behöver ange nyckelordet struct
på anropswebbplatsen. I det här exemplet elir du nyckelordet struct
när du anropar 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 |}
Det omvända mönstret – som struct
anger när indatatypen inte är en struct anonym post – kompileras inte.
Bädda in anonyma poster inom andra typer
Det är användbart att deklarera diskriminerade fackföreningar vars fall är register. Men om data i posterna är av samma typ som den diskriminerade unionen måste du definiera alla typer som ömsesidigt rekursiva. Om du använder anonyma poster undviks den här begränsningen. Vad som följer är en exempeltyp och funktion som mönstret matchar över den:
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
Kopiera och uppdatera uttryck
Anonyma poster stöder konstruktion med kopierings- och uppdateringsuttryck. Så här kan du till exempel skapa en ny instans av en anonym post som kopierar en befintligs data:
let data = {| X = 1; Y = 2 |}
let data' = {| data with Y = 3 |}
Men till skillnad från namngivna poster kan du med anonyma poster skapa helt olika formulär med kopierings- och uppdateringsuttryck. Följande exempel tar samma anonyma post från föregående exempel och expanderar den till en ny anonym post:
let data = {| X = 1; Y = 2 |}
let expandedData = {| data with Z = 3 |} // Gives {| X=1; Y=2; Z=3 |}
Det går också att skapa anonyma poster från instanser av namngivna poster:
type R = { X: int }
let data = { X = 1 }
let data' = {| data with Y = 2 |} // Gives {| X=1; Y=2 |}
Du kan också kopiera data till och från anonyma referensposter och struct-poster:
// 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 |}
Egenskaper för anonyma poster
Anonyma poster har ett antal egenskaper som är viktiga för att fullt ut förstå hur de kan användas.
Anonyma poster är nominella
Anonyma poster är nominella typer. De är bäst tänkta som namngivna posttyper (som också är nominella) som inte kräver en förhandsdeklaration.
Tänk dig följande exempel med två anonyma postdeklarationer:
let x = {| X = 1 |}
let y = {| Y = 1 |}
Värdena x
och y
har olika typer och är inte kompatibla med varandra. De är inte ekvatorliga och de är inte jämförbara. För att illustrera detta bör du överväga en namngiven postmotsvarighet:
type X = { X: int }
type Y = { Y: int }
let x = { X = 1 }
let y = { Y = 1 }
Det finns inget som skiljer sig från anonyma poster jämfört med deras namngivna postekvivalenter när det gäller typjämförelse eller jämförelse.
Anonyma poster använder strukturell likhet och jämförelse
Precis som posttyper är anonyma poster strukturellt likvärdiga och jämförbara. Detta gäller bara om alla typer av komponenter stöder likhet och jämförelse, till exempel med posttyper. För att stödja likhet eller jämförelse måste två anonyma poster ha samma "form".
{| 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|}
Anonyma poster kan serialiseras
Du kan serialisera anonyma poster precis som du kan med namngivna poster. Här är ett exempel med 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}"
Anonyma poster är användbara för att skicka lätta data via ett nätverk utan att behöva definiera en domän för dina serialiserade/deserialiserade typer i förväg.
Anonyma poster samverkar med anonyma C#-typer
Det är möjligt att använda ett .NET-API som kräver användning av anonyma C#-typer. Anonyma C#-typer är triviala att samverka med med hjälp av anonyma poster. I följande exempel visas hur du använder anonyma poster för att anropa en LINQ-överlagring som kräver en anonym typ:
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}"
Det finns en mängd andra API:er som används i hela .NET som kräver användning av att skicka in en anonym typ. Anonyma poster är ditt verktyg för att arbeta med dem.
Begränsningar
Anonyma poster har vissa begränsningar i användningen. Vissa är inbyggda i sin design, men andra kan ändras.
Begränsningar med mönstermatchning
Anonyma poster stöder inte mönstermatchning, till skillnad från namngivna poster. Det finns tre orsaker:
- Ett mönster måste ta hänsyn till varje fält i en anonym post, till skillnad från namngivna posttyper. Det beror på att anonyma poster inte stöder strukturell undertypning – de är nominella typer.
- På grund av (1) finns det ingen möjlighet att ha ytterligare mönster i ett mönstermatchningsuttryck, eftersom varje distinkt mönster skulle innebära en annan anonym posttyp.
- På grund av (2) skulle alla anonyma postmönster vara mer utförliga än användningen av "punkt"-notation.
Det finns ett öppet språkförslag som tillåter mönstermatchning i begränsade kontexter.
Begränsningar med föränderlighet
Det går för närvarande inte att definiera en anonym post med mutable
data. Det finns ett öppet språkförslag som tillåter föränderliga data.
Begränsningar med struct anonyma poster
Det går inte att deklarera struct anonyma poster som IsByRefLike
eller IsReadOnly
. Det finns ett öppet språkförslag för IsByRefLike
och IsReadOnly
anonyma poster.