Dopasowanie wzorca (F#)
Wzorce są regułami dotyczącymi przekształcania danych wejściowych.Są one używane w całym języku F# do porównywania danych ze strukturą logiczną lub strukturami, rozkładania danych do części składowych lub wyodrębnienia informacji z danych na różne sposoby.
Uwagi
Wzorce są stosowane w wielu konstrukcjach języka, takich jak wyrażenie match.Są one używane podczas przetwarzania argumentów funkcji w powiązaniach let, wyrażeniach lambda i procedurach obsługi wyjątków związanych z wyrażeniem try...with.Aby uzyskać więcej informacji, zobacz Wyrażenia dopasowania (F#), let — Powiązania (F#), Wyrażenia lambda: fun — Słowo kluczowe (F#), i Wyjątki: try...with — Wyrażenie (F#).
Na przykład w wyrażeniu match po symbol potoku następuje obiekt pattern.
porównaj expression z
| pattern [ when condition ] -> result-expression
...
Każdy deseń działa jako reguła przekształcania danych wejściowych w jakiś sposób.W wyrażeniu match każdy wzorzec jest badany kolejno, aby zobaczyć, czy dane wejściowe są zgodne z wzorcem.Jeśli zostanie znaleziona pasująca pozycja, wyrażenie obliczania wyniku jest wykonywane.Jeśli nie znaleziono pasującej pozycji, bada się następną regułę wzorca.Opcjonalne, jeśli część condition została wyjaśniona w Wyrażenia dopasowania (F#).
Obsługiwane wzorce przedstawiono w poniższej tabeli.W czasie wykonywania dane wejściowe są testowane w odniesieniu do każdego z następujących wzorów w określonej kolejności w tabeli, a wzory są stosowane cyklicznie, od pierwszego do ostatniego, tak jak pojawiają się one w kodzie, i od lewej do prawej dla wzorca w każdym wierszu.
Nazwa |
Opis |
Przykład |
---|---|---|
Wzór stałej |
Wszelkie wartości numeryczne, znak lub literał ciągu znaków, stała wyliczeniowa lub zdefiniowany identyfikator literału |
1.0, "test", 30, Color.Red |
Wzorzec identyfikatora |
Wartość case dyskryminowanej unii, etykieta wyjątku lub przypadek aktywnego wzoru |
Some(x) Failure(msg) |
Wzór zmiennej |
identifier |
a |
wzorzec as |
pattern jako identifier |
(a, b) as tuple1 |
Wzorzec LUB |
pattern1 | pattern2 |
([h] | [h; _]) |
Wzorzec AND |
pattern1 & pattern2 |
(a, b) & (_, "test") |
Wzór wad |
identifier :: list-identifier |
h :: t |
Wzorzec listy |
[ pattern_1; ... ; pattern_n ] |
[ a; b; c ] |
Wzorzec tablicy |
[| pattern_1; ..; pattern_n ] |
[| a; b; c |] |
Wzorzec ujęty w nawiasy |
( pattern ) |
( a ) |
Wzór krotki |
( pattern_1, ... , pattern_n ) |
( a, b ) |
Rejestruj wzorzec |
{ identifier1 = pattern_1; ... ; identifier_n = pattern_n } |
{ Name = name; } |
Wzór symboli wieloznacznych |
_ |
_ |
Wzorce wraz ze wskazaniem typu |
pattern : type |
a : int |
Wpisz wzór testu |
:?type [jako identifier] |
:? System.DateTime as dt |
Wzorzec zerowy |
wartość null |
null |
Wzory stałych
Wzorce stałych są stałymi wyliczeniowymi, liczbowymi, znakami i literałami ciągów (z uwzględnioną nazwą typu wyliczenia).Wyrażenie match, które ma tylko stałe wzorce, można porównać do wyrażenia case w innych językach.Dane wejściowe są porównywane z wartością literału a wzór pasuje, jeśli wartości są równe.Typ literału musi być zgodny z typem danych wejściowych.
Poniższy przykład pokazuje użycie wzorów literału i używa wzorów zmiennej oraz wzoru 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
Innym przykładem wzorca literału jest wzorzec oparty na wyliczeniu stałych.Musisz określić nazwę typu wyliczenia, gdy używasz stałych wyliczenia.
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
Wzorce identyfikatorów
Jeśli wzorzec jest ciągiem znaków, które tworzą prawidłowy identyfikator, forma identyfikatora określa, jak odbywa się dopasowanie do wzorca.Jeśli identyfikator ma więcej niż jeden znak i rozpoczyna się od wielkiej litery, kompilator próbuje wykonać dopasowanie do wzorca identyfikatora.Identyfikator dla tego wzoru może być wartością oznakowaną za pomocą atrybutu Literał, dyskryminowanego przypadku złożenia, identyfikatora wyjątku lub przypadku wzoru aktywnego.Jeśli pasujący identyfikator nie zostanie znaleziony, dopasowanie nie powiedzie się i następna reguła wzorca — wzorzec zmiennych — jest porównywana do danych wejściowych.
Rozróżniane wzorce połączeń mogą być przypadkami o prostych nazwach lub mogą mieć wartość, lub krotkę zawierającą wiele wartości.Jeśli istnieje wartości, należy określić identyfikator dla wartości.W przypadku spójnej kolekcji musisz podać wzorzec spójnej kolekcji z identyfikatorem dla każdego elementu spójnej kolekcji lub identyfikatorem o nazwie pola dla jednego lub więcej nazwanych pól złożenia.Zobacz przykłady kodu w tej sekcji.
Typ option to złożenie dyskryminowane, które ma dwa przypadki, Some i None.Jeden przypadek (Some) ma wartość, ale drugi (None) jest tylko nazwanym przypadkiem.W związku z tym Some musi mieć zmienną dla wartości skojarzonej z przypadkiem Some , ale None musi się pojawiać samodzielnie.W poniższym kodzie do zmiennej var1 jest podana wartość uzyskana przez dopasowanie do wielkości liter Some.
let printOption (data : int option) =
match data with
| Some var1 -> printfn "%d" var1
| None -> ()
W poniższym przykładzie w sumie rozłącznej PersonName znajdują się różne ciągi i znaki, które reprezentują możliwe formy nazw.Przypadkami złożeń dyskryminowanych są FirstOnly, LastOnly, i 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
Dla sum rozłącznych, które mają pola nazwane, należy używać znaku równości (=) do wyodrębnienia wartość nazwanego pola.Rozważmy na przykład sumę rozłączną z deklaracją jak następująca.
type Shape =
| Rectangle of height : float * width : float
| Circle of radius : float
Możesz użyć nazwanych pól w wyrażeniu dopasowania wzorca w następujący sposób.
let matchShape shape =
match shape with
| Rectangle(height = h) -> printfn "Rectangle with length %f" h
| Circle(r) -> printfn "Circle with radius %f" r
Korzystanie z nazwanego pola jest opcjonalne, więc w poprzednim przykładzie, zarówno Circle(r) jaki i Circle(radius = r) mają ten sam skutek.
Do określania wielu pól, użyj średnika (;) jako separatora.
match shape with
| Rectangle(height = h; width = w) -> printfn "Rectangle with height %f and width %f" h w
| _ -> ()
Aktywne wzorce umożliwiają zdefiniowanie bardziej złożonego niestandardowego wzorca dopasowania.Aby uzyskać więcej informacji na temat wzorców, zobacz Wzorce aktywne (F#).
Przypadek, w którym identyfikator jest wyjątkiem, jest używany podczas dopasowywania wzorca w kontekście obsługi wyjątków.Aby uzyskać informacje o dopasowywaniu do wzorca w obsłudze wyjątków, zobacz Wyjątki: try...with — Wyrażenie (F#).
Wzory zmiennej
Wzór zmiennej przypisuje wartość dopasowaną do nazwy zmiennej, która jest dostępna do użycia w wyrażeniu wykonywania znajdującym się z prawej strony symbolu ->.Sam wzorzec zmiennej nie pasuje do żadnych danych, ale wzorce zmiennej często pojawiają się w innych wzorcach, zatem umożliwiają tworzenie bardziej złożonych struktur, takich jak tablice i kolekcje, aby być rozłożone na zmienne.
Poniższy przykład ukazuje wzór zmiennej w ramach wzorca krotki.
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)
jako Wzorzec
Wzór as jest wzorem, który ma dołączoną klauzulę as.Klauzula as wiąże pasującą wartość z nazwą, która może być używana w wyrażeniu wykonywania wyrażenia match, lub, w przypadku gdy ten wzór jest używany w wiązaniu let, nazwa jest dodawana jako wiązanie do zakresu lokalnego.
Poniższy przykład wykorzystuje wzorzecas.
let (var1, var2) as tuple1 = (1, 2)
printfn "%d %d %A" var1 var2 tuple1
Wzorzec LUB
Wzór OR jest używany jeśli dane wejściowe można dopasować do wielu wzorców, a użytkownik chce w wyniku tego zrealizować ten sam kod.Typy obu stron wzorca OR muszą być zgodne.
Poniższy przykład demonstruje wzorzec 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)
Wzorzec AND
Wzór AND wymaga, aby dane wejściowe były zgodne z dwoma wzorcami.Typy obu stron wzorca AND muszą być zgodne.
Poniższy przykład jest jaki jak detectZeroTuple ukazany w sekcji Wzór krotki w dalszej części tego tematu, ale tutaj zarówno var1 jak i var2 są uzyskiwane jako wartości za pomocą wzorca 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)
Wzór wad
Wzór minusów służy do rozkładania listy na elementy pierwsze, głowa, oraz listy zawierającej wszystkie pozostałe elementy, ogon.
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
Wzorzec listy
Wzór listy umożliwia rozkładanie list na elementy.Sam wzorzec listy można dopasować tylko do list o określonej liczbie elementów.
// 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 [ ] )
Wzorzec tablicy
Wzór tablicy przypomina wzór listy i może być używany do rozkładania tablic o określonej długości.
// 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 "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 [| |] )
Wzorzec ujęty w nawiasy
Nawiasy mogą być grupowane wokół wzorców, aby osiągnąć pożądaną łączność.W poniższym przykładzie nawiasy są używane do kontrolowania łączność między wzorcem AND a wzorcem cons.
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
Wzór krotki
Wzorzec krotki pasuje do danych wejściowych w formularzu krotki i umożliwia rozkładanie krotki na elementy składowe za pomocą zmiennych pasujących do wzorca dla każdej pozycji w krotce.
Poniższy przykład pokazuje wzór krotki i używa wzorów literału, wzorów zmiennej oraz wzoru symboli wieloznacznych.
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)
Rejestruj wzorzec
Wzór rejestrowania jest używany do rozkładania rekordów w celu wyodrębnienia wartości pól.Wzór nie musi odwoływać się do wszystkich pól rekordu; wszelkie pominięte pola po prostu nie biorą udziału w dopasowywania i nie zostały wyodrębnione.
// 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"
Wzór symboli wieloznacznych
Wzór symboli wieloznacznych jest reprezentowany przez znak podkreślenia (_) i dopasowuje się do dowolnych danych wejściowych, z tym, że dane wejściowe są odrzucane zamiast bycia przypisywanymi do zmiennej.Wzór symboli wieloznacznych jest często używany w ramach innych wzorów jako symbol zastępczy dla wartości, które nie są potrzebne w wyrażeniu na prawo od symbolu ->.Wzór symboli wieloznacznych jest też często używany na końcu listy wzorców do dopasowywania niedopasowanych danych wejściowych.Wzór symboli wieloznacznych jest demonstrowany w wielu przykładach kodu w tym temacie.Zobacz kod poprzedzający dla jednego przykładu.
Wzorce mające wskazania typów
Wzorce mogą mieć wskazania typów.Zachowują się one jak inne adnotacje i prowadzą wnioskowanie jak inne adnotacje.Nawiasy są wymagane wokół wskazań typów we wzorcach.Poniższy kod przedstawia wzór, który ma wskazanie typu.
let detect1 x =
match x with
| 1 -> printfn "Found a 1!"
| (var1 : int) -> printfn "%d" var1
detect1 0
detect1 1
Wpisz wzór testu
Typ do którego wzór testowy jest używany do dopasowywania danych wejściowych do typu.Jeśli typ wejściowy pasuje do (lub typem pochodnym) typu określonego we wzorcu, dopasowanie powiedzie się.
Poniższy przykład demonstruje typ wzorca testowego.
open System.Windows.Forms
let RegisterControl(control:Control) =
match control with
| :? Button as button -> button.Text <- "Registered."
| :? CheckBox as checkbox -> checkbox.Text <- "Registered."
| _ -> ()
Wzorzec zerowy
Deseń zerowy pasuje do wartości zerowej, która może pojawić się podczas pracy z typami, które zezwalają na wartość zerową.Wzorce zerowe są często używane podczas współdziałania z kodem programu .NET Framework.Na przykład wartość zwracana przez interfejs API środowiska .NET może być wprowadzana do wyrażenia match.Można sterować przepływem programu na podstawie, czy wartość zwracana wynosi null, a także na podstawie innych cech zwróconej wartości.Możesz użyć wzorca null, aby zapobiec przedostawaniu się wartości null do pozostałej części programu.
Poniższy przykład używa wzoru null i wzoru i zmiennej.
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()