Bagikan melalui


Pencocokan Pola

Pola adalah aturan untuk mengubah data input. Pola digunakan di seluruh F# untuk membandingkan data dengan struktur atau struktur logis, menguraikan data menjadi bagian-bagian penyusunnya, atau mengekstrak informasi dari data dengan berbagai cara.

Keterangan

Pola digunakan dalam banyak konstruksi bahasa pemrograman, seperti ekspresi match. Pola digunakan saat Anda memproses argumen untuk fungsi dalam pengikatan let, ekspresi lambda, dan dalam penanganan pengecualian yang berkaitan dengan ekspresi try...with. Untuk informasi selengkapnya, lihat Ekspresi Pencocokan, le Bindings, Ekspresi Lambda: Kata kuncifun, dan Pengecualian: Ekspresi try...with.

Misalnya, dalam ekspresi match, polanya adalah apa yang mengikuti simbol pipa.

match expression with
| pattern [ when condition ] -> result-expression
...

Setiap pola bertindak sebagai aturan untuk mengubah input dengan cara tertentu. Dalam ekspresi match, setiap pola diperiksa secara bergantian untuk melihat apakah data input kompatibel dengan pola tersebut. Jika kecocokan ditemukan, ekspresi hasil akan dijalankan. Jika kecocokan tidak ditemukan, aturan pola selanjutnya akan diuji. Opsional ketika bagian kondisi dijelaskan dalam Ekspresi Pencocokan.

Pola yang didukung ditunjukkan dalam tabel berikut. Pada durasi, input diuji terhadap setiap pola berikut dalam urutan yang tercantum di dalam tabel dan pola diterapkan secara rekursif, dari pertama hingga terakhir saat mereka muncul dalam kode Anda dan dari kiri ke kanan untuk pola di setiap baris.

Nama Deskripsi Contoh
Pola konstanta Setiap harfiah numerik, karakter, atau string, konstanta enumerasi, atau pengidentifikasi harfiah yang ditentukan 1.0, , "test"30,Color.Red
Pola pengidentifikasi Nilai kasus dari discriminated union, label pengecualian, atau kasus pola aktif Some(x)

Failure(msg)
Pola variabel identifier a
Pola as pola sebagai pengidentifikasi (a, b) as tuple1
Pola OR pola1 | pola2 ([h] | [h; _])
Pola AND pattern1 & pattern2 (a, b) & (_, "test")
Pola kontra pengidentifikasi :: pengidentifikasi-daftar h :: t
Pola daftar [ pola_1; ... ; pola_n ] [ a; b; c ]
Pola array [| pola_1; ..; pola_n |] [| a; b; c |]
Pola tanda kurung ( pola ) ( a )
Pola tuple ( pola_1, ... , pola_n ) ( a, b )
Pola rekaman { pengidentifikasi1 = pola_1; ... ; pengidentifikasi_n = pola_n } { Name = name; }
Pola wildcard _ _
Pola bersama dengan anotasi jenis pola : jenis a : int
Pola pengujian jenis :? jenis [ sebagai pengidentifikasi ] :? System.DateTime as dt
Pola null nihil null
Pola nameof nameof expr nameof str

Pola Konstanta

Pola konstanta adalah harfiah numerik, karakter, dan string, konstanta enumerasi (dengan nama jenis enumerasi disertakan). Ekspresi match yang hanya memiliki pola konstanta dapat dibandingkan dengan pernyataan kasus dalam bahasa pemrograman lain. Input dibandingkan dengan nilai harfiah dan polanya cocok jika nilainya sama. Jenis harfiah harus kompatibel dengan jenis input.

Contoh berikut mendemonstrasikan penggunaan pola harfiah dan juga menggunakan pola variabel dan pola OR.

[<Literal>]
let Three = 3

let filter123 x =
    match x with
    // The following line contains literal patterns combined with an OR pattern.
    | 1 | 2 | Three -> printfn "Found 1, 2, or 3!"
    // The following line contains a variable pattern.
    | var1 -> printfn "%d" var1

for x in 1..10 do filter123 x

Contoh lain dari pola harfiah adalah pola yang didasarkan pada konstanta enumerasi. Anda harus menentukan nama jenis enumerasi ketika Anda menggunakan konstanta enumerasi.

type Color =
    | Red = 0
    | Green = 1
    | Blue = 2

let printColorName (color:Color) =
    match color with
    | Color.Red -> printfn "Red"
    | Color.Green -> printfn "Green"
    | Color.Blue -> printfn "Blue"
    | _ -> ()

printColorName Color.Red
printColorName Color.Green
printColorName Color.Blue

Pola Pengidentifikasi

Jika pola adalah rangkaian karakter yang membentuk pengidentifikasi yang valid, formulir pengidentifikasi menentukan bagaimana pola dicocokkan. Jika pengidentifikasi lebih panjang daripada karakter tunggal dan dimulai dengan karakter huruf besar, kompilator akan mencoba untuk mencocokkan dengan pola pengenal. Pengidentifikasi untuk pola ini dapat berupa nilai yang ditandai dengan atribut Literal, kasus discriminated union, pengidentifikasi pengecualian, atau kasus pola aktif. Jika tidak ditemukan pengidentifikasi yang cocok, pencocokan gagal dan aturan pola berikutnya, pola variabel, dibandingkan dengan input.

Pola discriminated union dapat berupa kasus bernama sederhana atau mereka dapat memiliki nilai atau tuple yang berisi beberapa nilai. Jika terdapat nilai, Anda harus menentukan pengidentifikasi untuk nilai tersebut. Dalam kasus tuple, Anda harus memberikan pola tuple pengidentifikasi untuk setiap elemen tupel atau pengidentifikasi dengan nama bidang untuk satu atau beberapa bidang union bernama. Lihat contoh kode di bagian ini untuk contoh.

Jenis option adalah discriminated union yang memiliki dua kasus, yaitu Some dan None. Satu kasus (Some) memiliki nilai, tetapi yang lain (None) hanyalah kasus bernama. Oleh karena itu, Some perlu memiliki variabel untuk nilai yang berkaitan dengan kasus Some, tetapi None harus muncul dengan sendirinya. Dalam kode berikut, variabel var1 diberikan nilai yang diperoleh dengan mencocokkannya dengan kasus Some.

let printOption (data : int option) =
    match data with
    | Some var1  -> printfn "%d" var1
    | None -> ()

Dalam contoh berikut, discriminated union PersonName berisi campuran string dan karakter yang mewakili kemungkinan formulir nama. Kasus-kasus discriminated union adalah FirstOnly, LastOnly, dan FirstLast.

type PersonName =
    | FirstOnly of string
    | LastOnly of string
    | FirstLast of string * string

let constructQuery personName =
    match personName with
    | FirstOnly(firstName) -> printf "May I call you %s?" firstName
    | LastOnly(lastName) -> printf "Are you Mr. or Ms. %s?" lastName
    | FirstLast(firstName, lastName) -> printf "Are you %s %s?" firstName lastName

Untuk discriminated union yang memiliki bidang bernama, Anda menggunakan tanda sama dengan (=) untuk mengekstrak nilai bidang bernama. Misalnya, pertimbangkan discriminated union dengan deklarasi seperti berikut.

type Shape =
    | Rectangle of height : float * width : float
    | Circle of radius : float

Anda dapat menggunakan bidang bernama dalam ekspresi pencocokan pola sebagai berikut.

let matchShape shape =
    match shape with
    | Rectangle(height = h) -> printfn $"Rectangle with length %f{h}"
    | Circle(r) -> printfn $"Circle with radius %f{r}"

Penggunaan bidang bernama bersifat opsional, jadi dalam contoh sebelumnya, Circle(r) dan Circle(radius = r) memiliki efek yang sama.

Saat Anda menentukan beberapa bidang, gunakan titik koma (;) sebagai pemisah.

match shape with
| Rectangle(height = h; width = w) -> printfn $"Rectangle with height %f{h} and width %f{w}"
| _ -> ()

Pola aktif memungkinkan Anda menentukan pencocokan pola kustom yang lebih kompleks. Untuk informasi selengkapnya tentang pola aktif, lihat Pola Aktif.

Kasus di mana pengidentifikasi merupakan sebuah pengecualian digunakan dalam pencocokan pola dalam konteks penanganan pengecualian. Untuk informasi tentang pencocokan pola dalam pengaturan pengecualian, lihat Pengecualian: try...with Ekspresi.

Pola Variabel

Pola variabel menetapkan nilai yang dicocokkan dengan nama variabel, yang kemudian tersedia untuk digunakan dalam ekspresi eksekusi di sebelah kanan simbol ->. Pola variabel saja cocok dengan input apa pun, tetapi pola variabel sering muncul di dalam pola lain, sehingga mengaktifkan struktur yang lebih kompleks, seperti tuple dan array untuk diurai menjadi variabel.

Contoh berikut mendemonstrasikan pola variabel di dalam pola tuple.

let function1 x =
    match x with
    | (var1, var2) when var1 > var2 -> printfn "%d is greater than %d" var1 var2
    | (var1, var2) when var1 < var2 -> printfn "%d is less than %d" var1 var2
    | (var1, var2) -> printfn "%d equals %d" var1 var2

function1 (1,2)
function1 (2, 1)
function1 (0, 0)

Pola as

Pola as adalah pola yang memiliki klausul as yang ditambahkan padanya. Klausul as mengikat nilai yang cocok ke nama yang dapat digunakan dalam ekspresi eksekusi dari ekspresi match, atau, dalam kasus di mana pola ini digunakan dalam pengikatan let, nama tersebut ditambahkan sebagai pengikatan ke cakupan lokal.

Contoh berikut menggunakan pola as.

let (var1, var2) as tuple1 = (1, 2)
printfn "%d %d %A" var1 var2 tuple1

Pola OR

Pola OR digunakan ketika data input dapat cocok dengan beberapa pola dan Anda ingin menjalankan kode yang sama sebagai hasilnya. Jenis kedua sisi pola OR harus kompatibel.

Contoh berikut mendemonstrasikan pola OR.

let detectZeroOR point =
    match point with
    | (0, 0) | (0, _) | (_, 0) -> printfn "Zero found."
    | _ -> printfn "Both nonzero."
detectZeroOR (0, 0)
detectZeroOR (1, 0)
detectZeroOR (0, 10)
detectZeroOR (10, 15)

Pola AND

Pola AND mengharuskan input cocok dengan dua pola. Jenis kedua sisi pola AND harus kompatibel.

Contoh berikut adalah seperti detectZeroTuple yang ditunjukkan dalam bagian Pola Tuple nanti dalam topik ini, tetapi di sini var1 dan var2 diperoleh sebagai nilai dengan menggunakan pola AND.

let detectZeroAND point =
    match point with
    | (0, 0) -> printfn "Both values zero."
    | (var1, var2) & (0, _) -> printfn "First value is 0 in (%d, %d)" var1 var2
    | (var1, var2)  & (_, 0) -> printfn "Second value is 0 in (%d, %d)" var1 var2
    | _ -> printfn "Both nonzero."
detectZeroAND (0, 0)
detectZeroAND (1, 0)
detectZeroAND (0, 10)
detectZeroAND (10, 15)

Pola Kontra

Pola kontra digunakan untuk menguraikan daftar menjadi elemen pertama kepala, dan daftar yang berisi elemen yang tersisa ekornya.

let list1 = [ 1; 2; 3; 4 ]

// This example uses a cons pattern and a list pattern.
let rec printList l =
    match l with
    | head :: tail -> printf "%d " head; printList tail
    | [] -> printfn ""

printList list1

Pola Daftar

Pola memungkinkan daftar diurai menjadi sejumlah elemen. Pola daftar itu sendiri hanya dapat mencocokkan daftar sejumlah elemen tertentu.

// This example uses a list pattern.
let listLength list =
    match list with
    | [] -> 0
    | [ _ ] -> 1
    | [ _; _ ] -> 2
    | [ _; _; _ ] -> 3
    | _ -> List.length list

printfn "%d" (listLength [ 1 ])
printfn "%d" (listLength [ 1; 1 ])
printfn "%d" (listLength [ 1; 1; 1; ])
printfn "%d" (listLength [ ] )

Pola Array

Pola array menyerupai pola daftar dan dapat digunakan untuk menguraikan array dengan panjang tertentu.

// This example uses array patterns.
let vectorLength vec =
    match vec with
    | [| var1 |] -> var1
    | [| var1; var2 |] -> sqrt (var1*var1 + var2*var2)
    | [| var1; var2; var3 |] -> sqrt (var1*var1 + var2*var2 + var3*var3)
    | _ -> failwith (sprintf "vectorLength called with an unsupported array size of %d." (vec.Length))

printfn "%f" (vectorLength [| 1. |])
printfn "%f" (vectorLength [| 1.; 1. |])
printfn "%f" (vectorLength [| 1.; 1.; 1.; |])
printfn "%f" (vectorLength [| |] )

Pola Tanda Kurung

Tanda kurung dapat dikelompokkan di sekitar pola untuk mencapai asosiativitas yang diinginkan. Dalam contoh berikut, tanda kurung digunakan untuk mengontrol asosiativitas antara pola AND dan pola kontra.

let countValues list value =
    let rec checkList list acc =
       match list with
       | (elem1 & head) :: tail when elem1 = value -> checkList tail (acc + 1)
       | head :: tail -> checkList tail acc
       | [] -> acc
    checkList list 0

let result = countValues [ for x in -10..10 -> x*x - 4 ] 0
printfn "%d" result

Pola Tuple

Pola tuple cocok dengan input dalam formulir tuple dan memungkinkan tuple diurai menjadi elemen penyusunnya dengan menggunakan variabel pencocokan pola untuk setiap posisi dalam tuple.

Contoh berikut mendemonstrasikan pola tuple dan juga menggunakan pola harfiah, pola variabel, dan pola wildcard.

let detectZeroTuple point =
    match point with
    | (0, 0) -> printfn "Both values zero."
    | (0, var2) -> printfn "First value is 0 in (0, %d)" var2
    | (var1, 0) -> printfn "Second value is 0 in (%d, 0)" var1
    | _ -> printfn "Both nonzero."
detectZeroTuple (0, 0)
detectZeroTuple (1, 0)
detectZeroTuple (0, 10)
detectZeroTuple (10, 15)

Pola Rekaman

Pola rekaman digunakan untuk mengurai rekaman untuk mengekstrak nilai bidang. Pola tidak harus mereferensikan semua bidang rekaman; setiap bidang yang dihilangkan tidak berpartisipasi dalam pencocokan dan tidak diekstraksi.

// This example uses a record pattern.

type MyRecord = { Name: string; ID: int }

let IsMatchByName record1 (name: string) =
    match record1 with
    | { MyRecord.Name = nameFound; MyRecord.ID = _; } when nameFound = name -> true
    | _ -> false

let recordX = { Name = "Parker"; ID = 10 }
let isMatched1 = IsMatchByName recordX "Parker"
let isMatched2 = IsMatchByName recordX "Hartono"

Pola Wildcard

Pola wildcard diwakili oleh karakter garis bawah (_) dan cocok dengan input apa pun, sama seperti pola variabel, kecuali bahwa input dibuang alih-alih ditetapkan ke variabel. Pola wildcard sering digunakan dalam pola lain sebagai tempat penampung untuk nilai yang tidak dibutuhkan dalam ekspresi di sebelah kanan simbol ->. Pola wildcard juga sering digunakan di akhir daftar pola untuk mencocokkan input yang tidak cocok. Pola wildcard didemonstrasikan dalam banyak contoh kode dalam topik ini. Lihat kode sebelumnya sebagai salah satu contoh.

Pola yang Memiliki Anotasi Jenis

Pola dapat memiliki anotasi jenis. Mereka berperilaku seperti anotasi jenis lain dan memandu inferensi seperti anotasi jenis lainnya. Tanda kurung dibutuhkan di sekitar anotasi jenis dalam pola. Kode berikut menunjukkan pola yang memiliki anotasi jenis.

let detect1 x =
    match x with
    | 1 -> printfn "Found a 1!"
    | (var1 : int) -> printfn "%d" var1
detect1 0
detect1 1

Pola Pengujian Jenis

Pola pengujian jenis digunakan untuk mencocokkan input dengan sebuah tipe. Jika jenis input cocok dengan (atau merupakan tipe turunan dari) tipe yang ditentukan dalam pola, pencocokan berhasil.

Contoh berikut mendemonstrasikan pola pengujian jenis.

open System.Windows.Forms

let RegisterControl(control:Control) =
    match control with
    | :? Button as button -> button.Text <- "Registered."
    | :? CheckBox as checkbox -> checkbox.Text <- "Registered."
    | _ -> ()

Jika Anda hanya memeriksa apakah sebuah pengidentifikasi merupakan tipe turunan tertentu, Anda tidak membutuhkan bagian as identifier dari pola, seperti yang ditunjukkan dalam contoh berikut:

type A() = class end
type B() = inherit A()
type C() = inherit A()

let m (a: A) =
    match a with
    | :? B -> printfn "It's a B"
    | :? C -> printfn "It's a C"
    | _ -> ()

Pola Null

Pola null cocok dengan nilai null yag dapat muncul saat Anda bekerja dengan jenis yang memungkinkan nilai null. Pola null sering digunakan saat berinteroperasi dengan kode .NET Framework. Misalnya, nilai pengembalian dari API .NET mungkin merupakan input ke ekspresi match. Anda dapat mengontrol aliran program berdasarkan apakah nilai pengembaliannya adalah null dan juga berdasarkan karakteristik lain dari nilai pengembalian. Anda dapat menggunakan pola null untuk mencegah nilai null menyebar ke seluruh program Anda.

Contoh berikut menggunakan pola null dan pola variabel.

let ReadFromFile (reader : System.IO.StreamReader) =
    match reader.ReadLine() with
    | null -> printfn "\n"; false
    | line -> printfn "%s" line; true

let fs = System.IO.File.Open("..\..\Program.fs", System.IO.FileMode.Open)
let sr = new System.IO.StreamReader(fs)
while ReadFromFile(sr) = true do ()
sr.Close()

Pola nameof

Pola nameof cocok dengan string ketika nilainya sama dengan ekspresi yang mengikuti kata kunci nameof. contohnya:

let f (str: string) =
    match str with
    | nameof str -> "It's 'str'!"
    | _ -> "It is not 'str'!"

f "str" // matches
f "asdf" // does not match

Lihat operator nameof untuk informasi tentang nama yang dapat Anda ambil.

Lihat juga