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.
Nilai fungsi F#, metode, properti, dan jenis agregat seperti kelas, rekaman, dan serikat yang didiskriminasi dapat bersifat umum. Konstruksi generik berisi setidaknya satu parameter jenis, yang biasanya disediakan oleh pengguna konstruksi generik. Fungsi dan jenis generik memungkinkan Anda menulis kode yang berfungsi dengan berbagai jenis tanpa mengulangi kode untuk setiap jenis. Membuat generik kode Anda bisa sederhana dalam F#, karena seringkali kode Anda secara implisit disimpulkan untuk umum oleh inferensi jenis kompilator dan mekanisme generalisasi otomatis.
Sintaksis
// Explicitly generic function.
let function-name<type-parameters> parameter-list =
function-body
// Explicitly generic method.
[ static ] member object-identifier.method-name<type-parameters> parameter-list [ return-type ] =
method-body
// Explicitly generic class, record, interface, structure,
// or discriminated union.
type type-name<type-parameters> type-definition
Komentar
Deklarasi fungsi atau jenis generik secara eksplisit mirip dengan fungsi atau jenis non-generik, kecuali untuk spesifikasi (dan penggunaan) parameter jenis, dalam tanda kurung sudut setelah fungsi atau nama jenis.
Deklarasi sering secara implisit generik. Jika Anda tidak sepenuhnya menentukan jenis setiap parameter yang digunakan untuk menyusun fungsi atau jenis, pengkompilasi mencoba menyimpulkan jenis setiap parameter, nilai, dan variabel dari kode yang Anda tulis. Untuk informasi selengkapnya, lihat Mengetik Inferensi. Jika kode untuk jenis atau fungsi Anda tidak membatasi jenis parameter, fungsi atau jenisnya secara implisit generik. Proses ini diberi nama generalisasi otomatis. Ada beberapa batasan pada generalisasi otomatis. Misalnya, jika pengkompilasi F# tidak dapat menyimpulkan jenis untuk konstruksi generik, pengkompilasi melaporkan kesalahan yang mengacu pada pembatasan yang disebut pembatasan nilai. Dalam hal ini, Anda mungkin harus menambahkan beberapa anotasi jenis. Untuk informasi selengkapnya tentang generalisasi otomatis dan pembatasan nilai, dan cara mengubah kode Anda untuk mengatasi masalah, lihat Generalisasi Otomatis.
Dalam sintaks sebelumnya, type-parameters adalah daftar parameter yang dipisahkan koma yang mewakili jenis yang tidak diketahui, yang masing-masing dimulai dengan tanda kutip tunggal, secara opsional dengan klausa batasan yang selanjutnya membatasi jenis apa yang dapat digunakan untuk parameter jenis tersebut. Untuk sintaks untuk klausa batasan dari berbagai jenis dan informasi lain tentang batasan, lihat Batasan.
Definisi jenis dalam sintaks sama dengan definisi jenis untuk jenis non-generik. Ini termasuk parameter konstruktor untuk jenis kelas, klausul opsional as , simbol yang sama, bidang rekaman, inherit klausa, pilihan untuk gabungan yang diskriminasi, let dan do pengikatan, definisi anggota, dan apa pun yang diizinkan dalam definisi jenis non-generik.
Elemen sintaks lainnya sama dengan elemen untuk fungsi dan jenis non-generik. Misalnya, pengidentifikasi objek adalah pengidentifikasi yang mewakili objek yang berisi itu sendiri.
Properti, bidang, dan konstruktor tidak boleh lebih umum daripada jenis penutup. Selain itu, nilai dalam modul tidak boleh generik.
Konstruksi Generik Implisit
Ketika pengkompilasi F# menyimpulkan jenis dalam kode Anda, ia secara otomatis memperlakukan fungsi apa pun yang dapat generik sebagai generik. Jika Anda menentukan jenis secara eksplisit, seperti jenis parameter, Anda mencegah generalisasi otomatis.
Dalam contoh kode berikut, makeList bersifat umum, meskipun parameter maupun parameternya tidak dinyatakan secara eksplisit sebagai generik.
let makeList a b = [ a; b ]
Tanda tangan fungsi disimpulkan menjadi 'a -> 'a -> 'a list. Perhatikan bahwa a dan b dalam contoh ini disimpulkan memiliki jenis yang sama. Ini karena mereka disertakan dalam daftar bersama-sama, dan semua elemen daftar harus dari jenis yang sama.
Anda juga dapat membuat fungsi generik dengan menggunakan sintaks tanda kutip tunggal dalam anotasi jenis untuk menunjukkan bahwa jenis parameter adalah parameter jenis generik. Dalam kode berikut, function1 bersifat umum karena parameternya dideklarasikan dengan cara ini, sebagai parameter jenis.
let function1 (x: 'a) (y: 'a) = printfn "%A %A" x y
Konstruksi Generik Secara Eksplisit
Anda juga dapat membuat fungsi generik dengan secara eksplisit mendeklarasikan parameter jenisnya dalam tanda kurung sudut (<type-parameter>). Kode berikut mengilustrasikan hal ini.
let function2<'T> (x: 'T) (y: 'T) = printfn "%A, %A" x y
Menggunakan Konstruksi Generik
Saat Anda menggunakan fungsi atau metode generik, Anda mungkin tidak perlu menentukan argumen jenis. Pengkompilasi menggunakan inferensi jenis untuk menyimpulkan argumen jenis yang sesuai. Jika masih ada ambiguitas, Anda dapat menyediakan argumen jenis dalam tanda kurung sudut, yang memisahkan beberapa argumen jenis dengan koma.
Kode berikut menunjukkan penggunaan fungsi yang ditentukan di bagian sebelumnya.
// In this case, the type argument is inferred to be int.
function1 10 20
// In this case, the type argument is float.
function1 10.0 20.0
// Type arguments can be specified, but should only be specified
// if the type parameters are declared explicitly. If specified,
// they have an effect on type inference, so in this example,
// a and b are inferred to have type int.
let function3 a b =
// The compiler reports a warning:
function1<int> a b
// No warning.
function2<int> a b
Nota
Ada dua cara untuk merujuk ke jenis generik berdasarkan nama. Misalnya, list<int> dan int list adalah dua cara untuk merujuk ke jenis list generik yang memiliki argumen intjenis tunggal . Bentuk terakhir hanya digunakan secara konvensional dengan jenis F# bawaan seperti list dan option. Jika ada beberapa argumen jenis, Anda biasanya menggunakan sintaks Dictionary<int, string> tetapi Anda juga dapat menggunakan sintaks (int, string) Dictionary.
Kartubebas sebagai Argumen Tipe
Untuk menentukan bahwa argumen tipe harus disimpulkan oleh pengkompilasi, Anda dapat menggunakan garis bawah, atau simbol kartubebas (_), bukan argumen jenis bernama. Ini ditunjukkan dalam kode berikut.
let printSequence (sequence1: Collections.seq<_>) =
Seq.iter (fun elem -> printf "%s " (elem.ToString())) sequence1
Batasan dalam Jenis dan Fungsi Generik
Dalam jenis generik atau definisi fungsi, Anda hanya dapat menggunakan konstruksi yang diketahui tersedia pada parameter jenis generik. Ini diperlukan untuk mengaktifkan verifikasi fungsi dan panggilan metode pada waktu kompilasi. Jika Anda mendeklarasikan parameter jenis Anda secara eksplisit, Anda dapat menerapkan batasan eksplisit ke parameter jenis generik untuk memberi tahu pengkompilasi bahwa metode dan fungsi tertentu tersedia. Namun, jika Anda mengizinkan pengkompilasi F# untuk menyimpulkan jenis parameter generik Anda, itu akan menentukan batasan yang sesuai untuk Anda. Untuk informasi selengkapnya, lihat Batasan.
Parameter Jenis yang Diselesaikan Secara Statis
Ada dua jenis parameter jenis yang dapat digunakan dalam program F#. Yang pertama adalah parameter jenis generik dari jenis yang dijelaskan di bagian sebelumnya. Jenis parameter jenis pertama ini setara dengan parameter jenis generik yang digunakan dalam bahasa seperti Visual Basic dan C#. Jenis parameter jenis lainnya khusus untuk F# dan disebut sebagai parameter jenis yang diselesaikan secara statis. Untuk informasi tentang konstruksi ini, lihat Parameter Jenis yang Diselesaikan Secara Statis.
Contoh
// A generic function.
// In this example, the generic type parameter 'a makes function3 generic.
let function3 (x: 'a) (y: 'a) = printf "%A %A" x y
// A generic record, with the type parameter in angle brackets.
type GR<'a> = { Field1: 'a; Field2: 'a }
// A generic class.
type C<'a>(a: 'a, b: 'a) =
let z = a
let y = b
member this.GenericMethod(x: 'a) = printfn "%A %A %A" x y z
// A generic discriminated union.
type U<'a> =
| Choice1 of 'a
| Choice2 of 'a * 'a
type Test() =
// A generic member
member this.Function1<'a>(x, y) = printfn "%A, %A" x y
// A generic abstract method.
abstract abstractMethod<'a, 'b> : 'a * 'b -> unit
override this.abstractMethod<'a, 'b>(x: 'a, y: 'b) = printfn "%A, %A" x y