Umum

Nilai, metode, properti, dan jenis agregat fungsi F# seperti kelas, data, dan gabungan 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 kode Anda generik prosesnya sederhana di F#, karena sering kali kode Anda secara implisit disimpulkan sebagai generik oleh inferensi jenis pengompilasi dan mekanisme generalisasi otomatis.

Sintaks

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

Keterangan

Deklarasi fungsi atau jenis generik 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 generik secara implisit. Jika Anda tidak sepenuhnya menentukan jenis setiap parameter yang digunakan untuk menyusun fungsi atau jenis, pengompilasi mencoba untuk menyimpulkan jenis setiap parameter, nilai, dan variabel dari kode yang Anda tulis. Untuk informasi selengkapnya, lihat Inferensi Jenis. Jika kode untuk jenis atau fungsi Anda tidak membatasi jenis parameter, maka fungsi atau jenisnya generik secara implisit. Proses ini diberi nama generalisasi otomatis. Ada beberapa batasan pada generalisasi otomatis. Misalnya, jika pengompilasi F# tidak dapat menyimpulkan jenis untuk konstruksi generik, pengompilasi melaporkan kesalahan yang mengacu pada pembatasan bernama pembatasan nilai. Dalam hal ini, Anda mungkin harus menambahkan beberapa anotasi jenis. Untuk informasi selengkapnya tentang generalisasi otomatis dan pembatasan nilai, serta cara mengubah kode Anda untuk mengatasi masalah tersebut, lihat Generalisasi Otomatis.

Dalam sintaks sebelumnya, type-parameters adalah daftar parameter yang dipisahkan koma dan mewakili jenis yang tidak diketahui. Masing-masing parameter dimulai dengan tanda kutip tunggal, secara opsional dengan klausa batasan yang selanjutnya membatasi jenis apa yang dapat digunakan untuk parameter jenis tersebut. Untuk sintaks pada klausa batasan dari berbagai jenis dan informasi lainnya tentang batasan, lihat Batasan.

type-definition dalam sintaks sama dengan definisi jenis untuk jenis non-generik. Ini termasuk parameter konstruktor untuk jenis kelas, klausul as opsional, simbol yang sama, bidang data, klausa inherit, pilihan untuk gabungan yang diskriminasi, pengikatan let dan do, definisi anggota, dan apa pun yang diizinkan dalam definisi jenis non-generik.

Elemen sintaks lainnya sama dengan yang untuk fungsi dan jenis non-generik. Misalnya, object-identifier adalah pengidentifikasi yang mewakili objek yang berisi itu sendiri.

Properti, bidang, dan konstruktor tidak boleh lebih generik daripada jenis penutup. Selain itu, nilai dalam modul tidak dapat bersifat generik.

Konstruksi Generik secara Implisit

Ketika menyimpulkan jenis dalam kode Anda, pengompilasi F# secara otomatis memperlakukan fungsi apa pun yang dapat bersifat generik sebagai generik. Jika Anda menentukan jenis secara eksplisit, seperti jenis parameter, Anda akan mencegah generalisasi otomatis.

Dalam contoh kode berikut, makeList bersifat generik, meskipun kode atau parameternya tidak dinyatakan secara eksplisit sebagai generik.

let makeList a b =
    [a; b]

Tanda tangan fungsi disimpulkan sebagai 'a -> 'a -> 'a list. Perhatikan bahwa a dan b dalam contoh ini disimpulkan memiliki jenis yang sama. Hal ini karena keduanya termasuk dalam daftar bersama, dan semua elemen daftar harus dari jenis yang sama.

Anda juga dapat membuat fungsi generik menggunakan sintaks tanda kutip tunggal dalam anotasi jenis untuk menunjukkan bahwa jenis parameter adalah parameter jenis generik. Dalam kode berikut, function1 bersifat generik karena parameternya dinyatakan 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 mendeklarasikan secara eksplisit parameter jenisnya dalam kurung sudut (<type-parameter>). Kode berikut menggambarkan hal ini.

let function2<'T> (x: 'T) (y: 'T) =
    printfn "%A, %A" x y

Menggunakan Konstruksi Generik

Saat menggunakan fungsi atau metode generik, Anda mungkin tidak perlu menentukan jenis argumen. Pengompilasi menggunakan inferensi jenis untuk menyimpulkan argumen jenis yang sesuai. Jika masih ada ambiguitas, Anda dapat memberikan argumen jenis dalam tanda kurung sudut, yang memisahkan beberapa argumen jenis dengan koma.

Kode berikut menunjukkan penggunaan fungsi yang didefinisikan 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

Catatan

Ada dua cara untuk merujuk ke jenis generik berdasarkan nama. Misalnya, list<int> dan int list adalah dua cara untuk merujuk ke jenis generik list yang memiliki argumen jenis tunggal int. Bentuk terakhir secara konvensional hanya digunakan 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.

Wildcard sebagai Argumen Jenis

Untuk menentukan bahwa argumen jenis harus disimpulkan oleh pengompilasi, Anda dapat menggunakan garis bawah, atau simbol wildcard (_), sebagai ganti argumen jenis bernama. Hal ini ditunjukkan dalam segmen 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. Hal ini diperlukan untuk mengaktifkan verifikasi fungsi dan panggilan metode pada waktu kompilasi. Jika mendeklarasikan parameter jenis Anda secara eksplisit, Anda dapat menerapkan batasan eksplisit ke parameter jenis generik untuk memberi tahu pengompilasi bahwa metode dan fungsi tertentu tersedia. Namun, jika Anda mengizinkan pengompilasi F # untuk menyimpulkan jenis parameter generik Anda, ini akan menentukan batasan yang sesuai untuk Anda. Untuk informasi selengkapnya, lihat Batasan.

Parameter Jenis yang Diselesaikan secara Statik

Ada dua parameter jenis yang bisa digunakan dalam program F#. Pertama adalah parameter jenis generik dari yang dijelaskan di bagian sebelumnya. Parameter jenis pertama ini setara dengan parameter jenis generik yang digunakan dalam bahasa seperti Visual Basic dan C#. Parameter jenis lain bersifat khusus untuk F# dan disebut sebagai parameter jenis yang diselesaikan secara statik. 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

Lihat juga