Bagikan melalui


Parameter Jenis yang Diselesaikan Secara Statis

Parameter jenis yang diselesaikan secara statis adalah parameter jenis yang diganti dengan jenis aktual pada waktu kompilasi, bukan pada waktu proses.

Sintaks

'type-parameter

Hingga versi 7.0 dari F#, seseorang harus menggunakan sintaks berikut

^type-parameter

Keterangan

Dalam F#, ada dua jenis parameter jenis yang berbeda. Jenis pertama adalah parameter jenis generik standar. Parameter tersebut setara dengan parameter jenis generik dalam bahasa .NET lainnya. Jenis lainnya diselesaikan secara statis dan hanya dapat digunakan dalam fungsi inlined.

Parameter jenis yang diselesaikan secara statis terutama berguna dalam hubungannya dengan batasan anggota, yang merupakan batasan yang memungkinkan Anda untuk menentukan bahwa argumen jenis harus memiliki anggota atau anggota tertentu agar dapat digunakan. Tidak ada cara untuk membuat batasan semacam ini dengan menggunakan parameter jenis generik biasa.

Tabel berikut ini meringkas kesamaan dan perbedaan antara dua jenis parameter jenis.

Fitur Generik Diselesaikan secara statis
Waktu resolusi Waktu jalan Waktu kompilasi
Batasan anggota Tidak dapat digunakan dengan batasan anggota. Dapat digunakan dengan batasan anggota.
Pembuatan kode Jenis (atau metode) dengan parameter jenis generik standar menghasilkan generasi jenis atau metode generik tunggal. Beberapa instansiasi jenis dan metode dihasilkan, satu untuk setiap jenis yang diperlukan.
Gunakan dengan jenis Dapat digunakan pada jenis. Tidak dapat digunakan pada jenis.
Gunakan dengan fungsi sebaris Fungsi sebaris tidak dapat diparameterkan dengan parameter jenis generik standar. Jika input tidak sepenuhnya umum, pengkompilasi F# mengkhususkannya atau, jika tidak ada opsi untuk mengkhususkan diri, memberikan kesalahan. Parameter jenis yang diselesaikan secara statis tidak dapat digunakan pada fungsi atau metode yang tidak sebaris.

Banyak fungsi pustaka inti F#, terutama operator, memiliki parameter jenis yang diselesaikan secara statis. Fungsi dan operator ini sebaris, dan menghasilkan pembuatan kode yang efisien untuk komputasi numerik.

Metode dan fungsi sebaris yang menggunakan operator, atau menggunakan fungsi lain yang memiliki parameter jenis yang diselesaikan secara statis, juga dapat menggunakan parameter jenis yang diselesaikan secara statis sendiri. Seringkali, ketik inferensi menyimpulkan fungsi sebaris tersebut untuk memiliki parameter jenis yang diselesaikan secara statis. Contoh berikut mengilustrasikan definisi operator yang disimpulkan memiliki parameter jenis yang diselesaikan secara statis.

let inline (+@) x y = x + x * y
// Call that uses int.
printfn "%d" (1 +@ 1)
// Call that uses float.
printfn "%f" (1.0 +@ 0.5)

Jenis (+@) yang diselesaikan didasarkan pada penggunaan keduanya (+) dan (*), yang keduanya menyebabkan inferensi jenis menyimpulkan batasan anggota pada parameter jenis yang diselesaikan secara statis. Jenis yang diselesaikan, seperti yang ditunjukkan dalam interpreter F#, adalah sebagai berikut.

'a -> 'c -> 'd
when ('a or 'b) : (static member ( + ) : 'a * 'b -> 'd) and
('a or 'c) : (static member ( * ) : 'a * 'c -> 'b)

Outputnya sebagai berikut.

2
1.500000

Contoh berikut mengilustrasikan penggunaan SRTP dengan metode dan metode statis:

type Record =
    { Number: int }
    member this.Double() = { Number = this.Number * 2 }
    static member Zero() = { Number = 0 }
    
let inline double<'a when 'a:(member Double: unit -> 'a)> (x: 'a) = x.Double()    
let inline zero<'a when 'a:(static member Zero: unit -> 'a)> () = 'a.Zero()

let r: Record = zero ()
let doubleR = double r

Dimulai dengan F# 7.0, Anda dapat menggunakan 'a.Zero() alih-alih harus mengulangi batasan seperti pada contoh di bawah ini.

Dimulai dengan F# 4.1, Anda juga dapat menentukan nama jenis konkret dalam tanda tangan parameter jenis yang diselesaikan secara statis. Dalam versi bahasa sebelumnya, nama jenis disimpulkan oleh kompilator, tetapi tidak dapat ditentukan dalam tanda tangan. Mulai dari F# 4.1, Anda juga dapat menentukan nama jenis konkret dalam tanda tangan parameter jenis yang diselesaikan secara statis. Berikut adalah contoh (harap dicatat bahwa dalam contoh ini, ^ masih harus digunakan karena penyederhanaan yang digunakan ' tidak didukung):

let inline konst x _ = x

type CFunctor() =
    static member inline fmap (f: ^a -> ^b, a: ^a list) = List.map f a
    static member inline fmap (f: ^a -> ^b, a: ^a option) =
        match a with
        | None -> None
        | Some x -> Some (f x)

    // default implementation of replace
    static member inline replace< ^a, ^b, ^c, ^d, ^e when ^a :> CFunctor and (^a or ^d): (static member fmap: (^b -> ^c) * ^d -> ^e) > (a, f) =
        ((^a or ^d) : (static member fmap : (^b -> ^c) * ^d -> ^e) (konst a, f))

    // call overridden replace if present
    static member inline replace< ^a, ^b, ^c when ^b: (static member replace: ^a * ^b -> ^c)>(a: ^a, f: ^b) =
        (^b : (static member replace: ^a * ^b -> ^c) (a, f))

let inline replace_instance< ^a, ^b, ^c, ^d when (^a or ^c): (static member replace: ^b * ^c -> ^d)> (a: ^b, f: ^c) =
        ((^a or ^c): (static member replace: ^b * ^c -> ^d) (a, f))

// Note the concrete type 'CFunctor' specified in the signature
let inline replace (a: ^a) (f: ^b): ^a0 when (CFunctor or  ^b): (static member replace: ^a *  ^b ->  ^a0) =
    replace_instance<CFunctor, _, _, _> (a, f)

Lihat juga