Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Rekaman anonim adalah agregat sederhana dari nilai bernama yang tidak perlu dideklarasikan sebelum digunakan. Anda dapat mendeklarasikannya sebagai struktur atau jenis referensi. Mereka adalah tipe referensi sebagai bawaan.
Sintaksis
Contoh berikut menunjukkan sintaks rekaman anonim. Item yang dibatasi sebagai [item]
opsional.
// 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; ...|}) ...
Penggunaan dasar
Pikirkan rekaman anonim sebagai jenis rekaman F# yang tidak perlu dideklarasikan sebelum instansiasi.
Misalnya, di sini bagaimana Anda dapat berinteraksi dengan fungsi yang menghasilkan rekaman anonim:
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
Contoh berikut meluas pada yang sebelumnya dengan printCircleStats
fungsi yang mengambil rekaman anonim sebagai input:
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
Memanggil printCircleStats
dengan jenis rekaman anonim yang tidak memiliki "bentuk" yang sama dengan jenis tipe masukan tidak akan dapat dikompilasi.
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"]'
Membuat rekaman anonim
Rekaman anonim juga dapat didefinisikan sebagai struct dengan kata kunci opsional struct
. Contoh berikut menambah yang sebelumnya dengan memproduksi dan mengonsumsi struktur rekaman anonim.
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
Inferensi Kekokohan Struktur
Rekor anonim struct juga memungkinkan "inferensi struktural" di mana Anda tidak perlu menentukan kata kunci struct
di lokasi pemanggilan. Dalam contoh ini, Anda menghilangkan struct
kata kunci saat memanggil 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 |}
Pola terbalik - menentukan struct
ketika tipe input bukan rekaman anonim tipe struct - akan gagal dikompilasi.
Menyematkan rekaman anonim dalam jenis lain
Sangat berguna untuk menyatakan serikat yang didiskriminasi yang kasusnya adalah catatan. Tetapi jika data dalam rekaman adalah jenis yang sama dengan persatuan terdiskriminasi, Anda harus menentukan semua jenis sebagai saling rekursif. Menggunakan rekaman anonim menghindari pembatasan ini. Berikut ini adalah contoh jenis dan fungsi yang cocok dengan pola di atasnya:
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
Menyalin dan memperbarui ekspresi
Catatan anonim mendukung pembangunan dengan ekspresi menyalin dan memperbarui. Misalnya, berikut cara membuat instans baru rekaman anonim yang menyalin data yang sudah ada:
let data = {| X = 1; Y = 2 |}
let data' = {| data with Y = 3 |}
Namun, tidak seperti rekaman bernama, rekaman anonim memungkinkan Anda membuat bentuk yang sama sekali berbeda dengan ekspresi penyalinan dan pembaruan. Contoh berikut mengambil rekaman anonim yang sama dari contoh sebelumnya dan memperluasnya ke dalam rekaman anonim baru:
let data = {| X = 1; Y = 2 |}
let expandedData = {| data with Z = 3 |} // Gives {| X=1; Y=2; Z=3 |}
Juga dimungkinkan untuk membentuk catatan anonim dari contoh catatan bernama.
type R = { X: int }
let data = { X = 1 }
let data' = {| data with Y = 2 |} // Gives {| X=1; Y=2 |}
Anda juga dapat menyalin data ke dan dari referensi dan menyusun rekaman anonim:
// 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 |}
Karakteristik rekaman anonim
Catatan anonim memiliki sejumlah karakteristik yang penting untuk sepenuhnya memahami bagaimana mereka dapat digunakan.
Rekaman anonim adalah nominal
Rekaman anonim adalah jenis nominal. Lebih baik dipandang sebagai tipe catatan bernama (yang juga nominal) yang tidak memerlukan deklarasi sebelumnya.
Pertimbangkan contoh berikut dengan dua deklarasi rekaman anonim:
let x = {| X = 1 |}
let y = {| Y = 1 |}
Nilai x
dan y
memiliki jenis yang berbeda dan tidak kompatibel satu sama lain. Mereka tidak setara dan tidak sebanding. Untuk mengilustrasikan hal ini, pertimbangkan rekaman bernama yang setara:
type X = { X: int }
type Y = { Y: int }
let x = { X = 1 }
let y = { Y = 1 }
Tidak ada yang secara inheren berbeda tentang rekaman anonim jika dibandingkan dengan rekaman bernama yang setara ketika mengenai kesetaraan atau perbandingan jenis.
Rekaman anonim menggunakan kesetaraan struktural dan perbandingan
Seperti jenis rekaman, rekaman anonim secara struktural setara dan sebanding. Ini hanya berlaku jika semua jenis konstituen mendukung kesetaraan dan perbandingan, seperti dengan jenis rekaman. Untuk mendukung kesetaraan atau perbandingan, dua rekaman anonim harus memiliki "bentuk" yang sama.
{| 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|}
Rekaman anonim dapat diserialisasikan
Anda dapat menserialisasikan rekaman anonim seperti yang Anda bisa dengan rekaman bernama. Berikut adalah contoh menggunakan 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}"
Rekaman anonim berguna untuk mengirim data ringan melalui jaringan tanpa perlu menentukan domain untuk jenis serial/deserialisasi Anda di muka.
Rekaman anonim berinteraksi dengan jenis anonim C#
Dimungkinkan untuk menggunakan .NET API yang memerlukan penggunaan jenis anonim C#. Tipe anonim C# mudah untuk dioperasikan dengan menggunakan record anonim. Contoh berikut menunjukkan cara menggunakan record anonim untuk memanggil overload LINQ yang memerlukan tipe anonim:
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}"
Ada banyak API lain yang digunakan di seluruh .NET yang memerlukan penggunaan passing dalam jenis anonim. Catatan anonim adalah alat Anda untuk bekerja dengan mereka.
Keterbatasan
Catatan anonim memiliki beberapa batasan dalam penggunaannya. Beberapa melekat pada desain mereka, tetapi yang lain dapat diubah.
Batasan dalam pencocokan pola
Rekaman anonim tidak mendukung pencocokan pola, tidak seperti rekaman bernama. Ada tiga alasan:
- Pola harus memperhitungkan setiap bidang rekaman anonim, tidak seperti jenis rekaman bernama. Ini karena rekaman anonim tidak mendukung subtipe struktural - mereka adalah jenis nominal.
- Karena (1), tidak ada kemampuan untuk memiliki pola tambahan dalam ekspresi kecocokan pola, karena setiap pola yang berbeda akan menyiratkan jenis rekaman anonim yang berbeda.
- Karena (2), pola rekaman anonim apa pun akan lebih verbose daripada penggunaan notasi "titik".
Ada saran bahasa terbuka untuk memungkinkan pencocokan pola dalam konteks terbatas.
Batasan pada mutabilitas
Saat ini tidak dimungkinkan untuk menentukan rekaman anonim dengan mutable
data. Ada saran bahasa terbuka untuk mengizinkan data yang dapat diubah.
Batasan dengan struktur catatan anonim
Tidak dimungkinkan untuk mendeklarasikan struct rekaman anonim sebagai IsByRefLike
atau IsReadOnly
. Ada usulan bahasa terbuka untuk IsByRefLike
dan IsReadOnly
rekaman anonim.