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.
Artikel ini menjelaskan dukungan bahasa untuk menentukan parameter dan meneruskan argumen ke fungsi, metode, dan properti. Ini termasuk informasi tentang cara melewati referensi dan cara menentukan dan menggunakan metode yang dapat mengambil jumlah variabel argumen.
Istilah parameter digunakan untuk menjelaskan nama untuk nilai yang diharapkan untuk disediakan. Istilah argumen digunakan untuk nilai yang disediakan untuk setiap parameter.
Parameter bisa ditentukan dalam bentuk tuple atau curried, atau dalam beberapa kombinasi keduanya. Anda bisa meneruskan argumen dengan menggunakan nama parameter eksplisit. Parameter dari metode dapat ditentukan sebagai opsional dan diberikan nilai default.
Pola parameter
Parameter yang disediakan ke fungsi dan metode, secara umum, pola dipisahkan oleh spasi. Ini berarti bahwa, pada prinsipnya, pola apa pun yang dijelaskan dalam Ekspresi Kecocokan dapat digunakan dalam daftar parameter untuk fungsi atau anggota.
Metode biasanya menggunakan bentuk tuple dari argumen passing. Ini mencapai hasil yang lebih jelas dari perspektif bahasa .NET lainnya karena bentuk tuple cocok dengan cara argumen diteruskan dalam metode .NET.
Bentuk curried paling sering digunakan dengan fungsi yang dibuat dengan menggunakan pengikatan let.
Pseudocode berikut menunjukkan contoh argumen tuple serta curried.
// Tuple form.
member this.SomeMethod(param1, param2) = ...
// Curried form.
let function1 param1 param2 = ...
Bentuk gabungan dimungkinkan ketika beberapa argumen berada dalam tuple dan beberapa tidak.
let function2 param1 (param2a, param2b) param3 = ...
Pola lain juga bisa digunakan dalam daftar parameter, tetapi jika pola parameter tidak cocok dengan semua input yang mungkin, mungkin ada kecocokan yang tidak lengkap pada durasi. Pengecualian MatchFailureException dihasilkan ketika nilai argumen tidak cocok dengan pola yang ditentukan dalam daftar parameter. Kompilator mengeluarkan peringatan saat pola parameter memungkinkan kecocokan yang tidak lengkap. Setidaknya satu pola lain biasanya berguna untuk daftar parameter, dan itu adalah pola wildcard. Anda menggunakan pola wildcard dalam daftar parameter ketika Anda hanya ingin mengabaikan argumen apa pun yang disediakan. Kode berikut mengilustrasikan penggunaan pola wildcard dalam daftar argumen.
let makeList _ = [ for i in 1 .. 100 -> i * i ]
// The arguments 100 and 200 are ignored.
let list1 = makeList 100
let list2 = makeList 200
Pola wildcard dapat berguna setiap kali Anda tidak memerlukan argumen yang diteruskan, seperti di titik masuk utama ke program, ketika Anda tidak tertarik dengan argumen baris perintah yang biasanya disediakan sebagai string array, seperti dalam kode berikut.
[<EntryPoint>]
let main _ =
printfn "Entry point!"
0
Pola lain yang terkadang digunakan dalam argumen adalah pola as, dan pola pengidentifikasi yang terkait dengan serikat yang didiskriminasi dan pola aktif. Anda bisa menggunakan pola gabungan yang didiskriminasi kasus tunggal sebagai berikut.
type Slice = Slice of int * int * string
let GetSubstring1 (Slice(p0, p1, text)) =
printfn "Data begins at %d and ends at %d in string %s" p0 p1 text
text[p0..p1]
let substring = GetSubstring1 (Slice(0, 4, "Et tu, Brute?"))
printfn "Substring: %s" substring
Outputnya sebagai berikut.
Data begins at 0 and ends at 4 in string Et tu, Brute?
Et tu
Pola aktif bisa berguna sebagai parameter, misalnya, saat mengubah argumen menjadi format yang diinginkan, seperti dalam contoh berikut:
type Point = { x : float; y : float }
let (| Polar |) { x = x; y = y} =
( sqrt (x*x + y*y), System.Math.Atan (y/ x) )
let radius (Polar(r, _)) = r
let angle (Polar(_, theta)) = theta
Anda bisa menggunakan pola as untuk menyimpan nilai yang cocok sebagai nilai lokal, seperti yang ditunjukkan dalam baris kode berikut.
let GetSubstring2 (Slice(p0, p1, text) as s) = s
Pola lain yang sesekali digunakan adalah fungsi yang membiarkan argumen terakhir tidak disebutkan namanya dengan penyediaan, sebagai isi fungsi, ekspresi lambda yang segera melakukan kecocokan pola pada argumen implisit. Contohnya adalah baris kode berikut ini.
let isNil = function [] -> true | _::_ -> false
Kode ini mendefinisikan fungsi yang mengambil daftar generik serta mengembalikan true jika daftar kosong, dan false jika sebaliknya. Penggunaan teknik tersebut bisa membuat kode lebih sulit dibaca.
Terkadang, pola yang melibatkan kecocokan yang tidak lengkap berguna, misalnya, jika Anda tahu bahwa daftar dalam program Anda hanya mempunyai tiga elemen, Anda mungkin menggunakan pola seperti berikut ini dalam daftar parameter.
let sum [a; b; c;] = a + b + c
Penggunaan pola yang mempunyai kecocokan yang tidak lengkap paling baik disediakan untuk pembuatan prototipe cepat dan penggunaan sementara lainnya. Pengompilasi akan mengeluarkan peringatan untuk kode tersebut. Pola tersebut tidak bisa mencakup kasus umum dari semua input yang mungkin dan oleh karena itu tidak cocok untuk API komponen.
Argumen bernama
Argumen untuk metode bisa ditentukan oleh posisi dalam daftar argumen yang dipisahkan koma, atau dapat diteruskan ke metode secara eksplisit dengan memberikan nama, diikuti dengan tanda sama dengan dan nilai yang akan diteruskan. Jika ditentukan dengan memberikan nama, mereka dapat muncul dalam urutan yang berbeda dari yang digunakan dalam deklarasi.
Argumen bernama dapat membuat kode lebih mudah dibaca dan lebih mudah beradaptasi dengan jenis perubahan tertentu dalam API, seperti menyusun ulang parameter metode.
Argumen bernama hanya diperbolehkan untuk metode, bukan untuk fungsi let terikat, nilai fungsi, atau ekspresi lambda.
Contoh kode berikut menunjukkan penggunaan dari argumen bernama.
type SpeedingTicket() =
member this.GetMPHOver(speed: int, limit: int) = speed - limit
let CalculateFine (ticket : SpeedingTicket) =
let delta = ticket.GetMPHOver(limit = 55, speed = 70)
if delta < 20 then 50.0 else 100.0
let ticket1 : SpeedingTicket = SpeedingTicket()
printfn "%f" (CalculateFine ticket1)
Dalam panggilan ke konstruktor kelas, Anda bisa mengatur nilai properti kelas dengan menggunakan sintaks yang mirip dengan argumen bernama. Contoh berikut menunjukkan sintaks ini.
type Account() =
let mutable balance = 0.0
let mutable number = 0
let mutable firstName = ""
let mutable lastName = ""
member this.AccountNumber
with get() = number
and set(value) = number <- value
member this.FirstName
with get() = firstName
and set(value) = firstName <- value
member this.LastName
with get() = lastName
and set(value) = lastName <- value
member this.Balance
with get() = balance
and set(value) = balance <- value
member this.Deposit(amount: float) = this.Balance <- this.Balance + amount
member this.Withdraw(amount: float) = this.Balance <- this.Balance - amount
let account1 = new Account(AccountNumber=8782108,
FirstName="Darren", LastName="Parker",
Balance=1543.33)
Untuk informasi selengkapnya, lihat Konstruktor (F#).
Teknik yang sama, dimaksudkan untuk memanggil setter properti, juga berlaku untuk metode pengembalian objek apa pun (seperti metode pabrik):
type Widget() =
member val Width = 1 with get,set
member val Height = 1 with get,set
type WidgetFactory =
static member MakeNewWidget() =
new Widget()
static member AdjustWidget(w: Widget) =
w
let w = WidgetFactory.MakeNewWidget(Width=10)
w.Width // = 10
w.Height // = 1
WidgetFactory.AdjustWidget(w, Height=10)
w.Height // = 10
Perhatikan bahwa anggota tersebut dapat melakukan pekerjaan arbitrer apa pun, sintaksnya secara efektif merupakan tangan singkat untuk memanggil setter properti sebelum mengembalikan nilai akhir.
Parameter opsional
F# mendukung dua bentuk parameter opsional yang berbeda untuk metode, masing-masing melayani tujuan yang berbeda:
Parameter opsional (asli F#)
Anda dapat menentukan parameter opsional untuk metode dengan menggunakan tanda tanya di depan nama parameter. Dari perspektif penerima panggilan, parameter opsional ditafsirkan sebagai jenis opsi F#, sehingga Anda dapat mengkuerinya dengan cara reguler jenis opsi dikueri, dengan menggunakan match ekspresi dengan Some dan None. Parameter opsional hanya diizinkan pada anggota, bukan pada fungsi yang dibuat dengan menggunakan pengikatan let.
Anda bisa meneruskan nilai opsional yang ada ke metode menurut nama parameter, seperti ?arg=None atau ?arg=Some(3), atau ?arg=arg. Ini dapat berguna saat membangun metode yang meneruskan argumen opsional ke metode yang lain.
Anda juga dapat menggunakan fungsi defaultArg, yang mengatur nilai default argumen opsional menggunakan bayangan. Fungsi defaultArg mengambil parameter opsional sebagai argumen pertama dan nilai default sebagai yang kedua. Tidak seperti ekstensi C#-style, fungsi ini memungkinkan penulis metode untuk memberi tahu apakah penelepon meneruskan nilai atau tidak.
Contoh berikut mengilustrasikan penggunaan dari parameter opsional.
type DuplexType =
| Full
| Half
type Connection(?rate0 : int, ?duplex0 : DuplexType, ?parity0 : bool) =
let duplex = defaultArg duplex0 Full
let parity = defaultArg parity0 false
let mutable rate = match rate0 with
| Some rate1 -> rate1
| None -> match duplex with
| Full -> 9600
| Half -> 4800
do printfn "Baud Rate: %d Duplex: %A Parity: %b" rate duplex parity
let conn1 = Connection(duplex0 = Full)
let conn2 = Connection(duplex0 = Half)
let conn3 = Connection(300, Half, true)
let conn4 = Connection(?duplex0 = None)
let conn5 = Connection(?duplex0 = Some(Full))
let optionalDuplexValue : option<DuplexType> = Some(Half)
let conn6 = Connection(?duplex0 = optionalDuplexValue)
Outputnya sebagai berikut.
Baud Rate: 9600 Duplex: Full Parity: false
Baud Rate: 4800 Duplex: Half Parity: false
Baud Rate: 300 Duplex: Half Parity: true
Baud Rate: 9600 Duplex: Full Parity: false
Baud Rate: 9600 Duplex: Full Parity: false
Baud Rate: 4800 Duplex: Half Parity: false
Anda juga dapat menentukan parameter opsional untuk menjadi jenis Opsi Nilai dengan menerapkan [<Struct>] atribut ke parameter tersebut.
type T() =
static member M([<Struct>] ?p : string) =
match p with
| ValueSome s -> printfn "%s" s
| ValueNone -> printfn "None"
Saat menggunakan parameter opsional yang didukung struct, seperti yang terlihat di atas, Anda akan menggunakan defaultValueArg alih-alih defaultArg mengatur nilai default parameter.
Parameter opsional (interop C#)
Untuk tujuan interop C#, Anda dapat menggunakan atribut [<Optional; DefaultParameterValue<(...)>] di F#, sehingga penelepon akan melihat argumen sebagai opsional. Ini setara dengan menentukan argumen sebagai opsional dalam C# seperti pada MyMethod(int i = 3). Formulir ini diperkenalkan dalam F# 4.1 untuk membantu memfasilitasi interoperatasi dengan kode C#.
open System
open System.Runtime.InteropServices
type C =
static member Foo([<Optional; DefaultParameterValue("Hello world")>] message) =
printfn $"{message}"
Anda juga bisa menentukan objek baru sebagai nilai parameter default. Misalnya, anggota Foo dapat memiliki CancellationToken opsional sebagai input:
open System.Threading
open System.Runtime.InteropServices
type C =
static member Foo([<Optional; DefaultParameterValue(CancellationToken())>] ct: CancellationToken) =
printfn $"{ct}"
Nilai yang diberikan sebagai argumen ke DefaultParameterValue harus cocok dengan jenis parameternya. Misalnya, hal berikut tidak diperbolehkan:
type C =
static member Wrong([<Optional; DefaultParameterValue("string")>] i:int) = ()
Dalam hal ini, pengompilasi menghasilkan peringatan dan akan mengabaikan kedua atribut seluruhnya. Perhatikan bahwa nilai null default harus diberi anotasi jenis; jika tidak, pengompilasi menyimpulkan jenis yang salah, yaitu, [<Optional; DefaultParameterValue(null:obj)>] o:obj.
Lewati menurut referensi
Meneruskan nilai F# menurut referensi melibatkan byrefs, yang merupakan jenis pointer terkelola. Panduan mengenai jenis mana yang akan digunakan adalah sebagai berikut:
- Gunakan
inref<'T>jika Anda hanya perlu membaca penunjuk. - Gunakan
outref<'T>jika Anda hanya perlu menulis ke penunjuk. - Gunakan
byref<'T>jika Anda perlu membaca dari serta menulis ke penunjuk.
let example1 (x: inref<int>) = printfn $"It's %d{x}"
let example2 (x: outref<int>) = x <- x + 1
let example3 (x: byref<int>) =
printfn $"It's %d{x}"
x <- x + 1
let test () =
// No need to make it mutable, since it's read-only
let x = 1
example1 &x
// Needs to be mutable, since we write to it
let mutable y = 2
example2 &y
example3 &y // Now 'y' is 3
Karena parameter adalah penunjuk dan nilainya dapat diubah, setiap perubahan pada nilai dipertahankan setelah eksekusi dari fungsi.
Anda dapat menggunakan tuple sebagai nilai kembali untuk menyimpan parameter out apa pun dalam metode pustaka .NET. Atau, Anda bisa memperlakukan parameter out sebagai parameter byref. Contoh kode berikut menggambarkan kedua cara.
// TryParse has a second parameter that is an out parameter
// of type System.DateTime.
let (b, dt) = System.DateTime.TryParse("12-20-04 12:21:00")
printfn "%b %A" b dt
// The same call, using an address of operator.
let mutable dt2 = System.DateTime.Now
let b2 = System.DateTime.TryParse("12-20-04 12:21:00", &dt2)
printfn "%b %A" b2 dt2
Array parameter
Kadang-kadang perlu untuk mendefinisikan fungsi yang mengambil sejumlah parameter jenis heterogen. Tidak akan praktis untuk membuat semua metode kelebihan beban yang mungkin untuk memperhitungkan semua jenis yang bisa digunakan. Implementasi .NET memberikan dukungan untuk metode tersebut melalui fitur array parameter. Metode yang mengambil array parameter dalam tanda tangannya dapat disediakan dengan jumlah parameter yang dapat berubah. Parameter dimasukkan ke dalam array. Jenis elemen array menentukan jenis parameter yang bisa diteruskan ke fungsi. Jika Anda menentukan array parameter dengan System.Object sebagai jenis elemen, maka kode klien bisa meneruskan nilai dari jenis apa pun.
Di F#, array parameter hanya bisa ditentukan dalam metode. Mereka tidak dapat digunakan dalam fungsi mandiri atau fungsi yang didefinisikan dalam modul.
Namun, fungsi seperti printfn mencapai perilaku serupa dengan menggunakan penentu format dan mengetik inferensi untuk menangani beberapa argumen secara dinamis. Fungsi printfn tidak bergantung pada array parameter; sebaliknya, ia menggunakan mekanisme pemformatan tipe aman F#untuk memproses berbagai jumlah argumen sambil memastikan pemeriksaan jenis waktu kompilasi.
Anda menentukan array parameter dengan menggunakan atribut ParamArray. Atribut ParamArray hanya bisa diterapkan ke parameter terakhir.
Kode berikut mengilustrasikan pemanggilan metode .NET yang mengambil array parameter dan definisi jenis di F# yang memiliki metode yang mengambil array parameter.
open System
type X() =
member this.F([<ParamArray>] args: Object[]) =
for arg in args do
printfn "%A" arg
[<EntryPoint>]
let main _ =
// call a .NET method that takes a parameter array, passing values of various types
Console.WriteLine("a {0} {1} {2} {3} {4}", 1, 10.0, "Hello world", 1u, true)
let xobj = new X()
// call an F# method that takes a parameter array, passing values of various types
xobj.F("a", 1, 10.0, "Hello world", 1u, true)
0
Saat dijalankan dalam proyek, output kode sebelumnya adalah sebagai berikut:
a 1 10 Hello world 1 True
"a"
1
10.0
"Hello world"
1u
true