Megosztás a következőn keresztül:


Névtelen rekordok

A névtelen rekordok a névvel ellátott értékek egyszerű összesítései, amelyeket nem kell deklarálni használat előtt. Deklarálhatja őket szerkezetként vagy referenciatípusként. Alapértelmezés szerint referenciatípusok.

Szemantika

Az alábbi példák a névtelen rekord szintaxisát mutatják be. Az [item] jelöléssel határolt elemek választhatóak.

// 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; ...|}) ...

Alapszintű használat

A névtelen rekordokat érdemes F# típusú rekordtípusoknak tekinteni, amelyeket nem kell deklarálni a példányosítás előtt.

Például az alábbi módon kezelheti egy névtelen rekordot előállító függvényt:

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

Az alábbi példa az előzőre bont ki egy printCircleStats függvényt, amely egy névtelen rekordot vesz fel bemenetként:

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

Az olyan névtelen rekordtípussal való hívás printCircleStats , amely nem ugyanazzal az "alakzattal" rendelkezik, mint a bemeneti típus, nem lesz lefordítva:

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"]'

Névtelen rekordok strukturálás

A névtelen rekordok strukturáltként is definiálhatók az opcionális struct kulcsszóval. Az alábbi példa egy strukturált névtelen rekord előállításával és felhasználásával bővíti az előzőt:

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

Strukturáltság következtetése

A névtelen rekordok strukturálása "strukturitási következtetést" is lehetővé tesz, ahol nem kell megadnia a kulcsszót struct a hívási helyen. Ebben a példában kihagyja a struct kulcsszót, amikor a printCircleStats hívást elvégzi.


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

A fordított minta – ha struct van megadva, amikor a bemeneti típus nem strukturált névtelen rekord – nem fog lefordulni.

Névtelen rekordok beágyazása más típusokba

Érdemes deklarálni azokat a hátrányos megkülönböztetést alkalmazó szakszervezeteket , amelyeknek az ügyei rekordnak számítanak. Ha azonban a rekordok adatai megegyeznek a diszkriminált egyesítés típusával, minden típust kölcsönösen rekurzívként kell definiálnia. A névtelen rekordok használata elkerüli ezt a korlátozást. Az alábbiakban egy példatípust és függvényt mutatunk be, amely egyezik a mintával:

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

Kifejezések másolása és frissítése

A névtelen rekordok másolási és frissítési kifejezésekkel támogatják a konstrukciót. Például az alábbi módon hozhat létre egy névtelen rekord új példányát, amely egy meglévő adatát másolja:

let data = {| X = 1; Y = 2 |}
let data' = {| data with Y = 3 |}

A névvel ellátott rekordoktól eltérően azonban a névtelen rekordok lehetővé teszik, hogy teljesen új és különböző alakzatokat hozzon létre másolási és frissítési kifejezésekkel. A következő példa ugyanazt a névtelen rekordot veszi fel az előző példából, és egy új névtelen rekordra bontja:

let data = {| X = 1; Y = 2 |}
let expandedData = {| data with Z = 3 |} // Gives {| X=1; Y=2; Z=3 |}

Névtelen rekordokat is létre lehet hozni nevesített rekordok példányaiból:

type R = { X: int }
let data = { X = 1 }
let data' = {| data with Y = 2 |} // Gives {| X=1; Y=2 |}

Az adatokat átmásolhatja a hivatkozásból és a hivatkozásból, és strukturálhatja a névtelen rekordokat:

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

Névtelen rekordok tulajdonságai

A névtelen rekordok számos olyan jellemzővel rendelkeznek, amelyek elengedhetetlenek a használatuk teljes megértéséhez.

A névtelen rekordok strukturális egyenlőséget és összehasonlítást használnak

A rekordtípusokhoz hasonlóan a névtelen rekordok is szerkezetileg egyenértékűek és összehasonlíthatók. Ez csak akkor igaz, ha minden összetevőtípus támogatja az egyenlőséget és az összehasonlítást, például a rekordtípusok esetében. Az egyenlőség vagy összehasonlítás támogatásához két névtelen rekordnak azonos "alakzattal" kell rendelkeznie.

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

A névtelen rekordok szerializálhatók

A névtelen rekordokat ugyanúgy szerializálhatja, mint a nevesített rekordokat. Íme egy példa a Newtonsoft.Json használatával:

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

A névtelen rekordok akkor hasznosak, ha egyszerű adatokat küldenek egy hálózaton anélkül, hogy tartományt kellene definiálni a szerializált/deszerializált típusokhoz elöl.

A névtelen rekordok c# névtelen típusokkal működnek együtt

Olyan .NET API is használható, amely C# névtelen típusok használatát igényli. A C# névtelen típusok triviálisak a névtelen rekordok használatával való együttműködéshez. Az alábbi példa bemutatja, hogyan hívhat névtelen rekordokat egy névtelen típust igénylő LINQ-túlterhelés meghívásához:

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

A .NET-ben számos más API-t is használnak, amelyek névtelen típusú továbbítást igényelnek. A névtelen rekordok a velük végzett munka eszközei.

Korlátozások

A névtelen rekordok használata bizonyos korlátozásokkal rendelkezik. Némelyik a kialakításuk velejárója, mások azonban módosíthatók.

A mintaegyezés korlátai

A névtelen rekordok nem támogatják a mintaegyezést, ellentétben az elnevezett rekordokkal. Három oka van:

  1. A mintának egy névtelen rekord minden mezőjét figyelembe kell vennie, ellentétben a nevesített rekordtípusokkal. Ennek az az oka, hogy a névtelen rekordok nem támogatják a szerkezeti altipizálást – pontos mezőegyeztetést igényelnek.
  2. Az (1) miatt nincs lehetőség arra, hogy a mintaegyeztetési kifejezésben további minták legyenek, mivel az egyes különálló minták más névtelen rekordtípust jelentenek.
  3. A (2) miatt minden névtelen rekordminta részletesebb lenne, mint a "pont" jelölés használata.

Van egy nyílt nyelvi javaslat, amely lehetővé teszi a mintaegyezést korlátozott környezetben.

A módosíthatóság korlátozásai

Egy névtelen rekord jelenleg nem határozható meg adatokkal mutable . Van egy nyílt nyelvi javaslat a módosítható adatok engedélyezésére.

Korlátozások névtelen rekordok strukturálása esetén

Nem lehet deklarálni a névtelen struktúrákat, mint IsByRefLike vagy IsReadOnly. Van egy nyílt nyelvi javaslat a rekordokra és IsByRefLike a névtelen rekordokraIsReadOnly.