Dela via


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:

  1. 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.
  2. 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.
  3. 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.