Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
A minták a bemeneti adatok átalakításának szabályai. Az F#-ban az adatok logikai struktúrával vagy struktúrákkal való összehasonlítására, az adatok alkotórészekké való lebontására vagy az adatokból származó információk különböző módokon történő kinyerésére használhatók.
Megjegyzések
A minták számos nyelvi szerkezetben használhatók, például a match kifejezésben. Azokat akkor használják, ha argumentumokat dolgoz fel let kötésekben, lambdakifejezésekben, és a try...with kifejezéshez társított kivételkezelőkben. További információ: Kifejezések egyeztetése, engedélyezi a kötéseket, Lambda-kifejezések: A fun kulcsszóés kivételek: A try...with kifejezés.
A match kifejezésben például a minta a pipa szimbólumot követi.
match expression with
| pattern [ when condition ] -> result-expression
...
Minden minta szabályként szolgál a bemenet valamilyen módon történő átalakításához. A match kifejezésben a rendszer minden mintát megvizsgál annak ellenőrzéséhez, hogy a bemeneti adatok kompatibilisek-e a mintával. Ha talál egyezést, a rendszer végrehajtja az eredménykifejezést. Ha nem talál egyezést, a következő mintaszabályt teszteli a rendszer. A választható, amikor feltétel rész szerepel a Kifejezésegyeztetésekcímű részben ismertetve.
A támogatott minták az alábbi táblázatban láthatók. Futásidőben a rendszer a következő minták mindegyikével teszteli a bemenetet a táblázatban felsorolt sorrendben, és a minták rekurzív módon lesznek alkalmazva, az elsőtől az utolsóig, ahogy azok megjelennek a kódban, és balról jobbra az egyes sorok mintáihoz.
| Név | Leírás | Példa |
|---|---|---|
| Állandó minta | Bármely numerikus, karakter- vagy sztringkonstans, enumerálási állandó vagy meghatározott literális azonosító |
1.0, "test", 30Color.Red |
| Azonosító minta | Diszkriminált unió esetértéke, kivételcímke vagy aktív mintázat esetértéke | Some(x)Failure(msg) |
| Változó minta | azonosító | a |
as minta |
mintaazonosítóként | (a, b) as tuple1 |
| VAGY minta | minta1 | minta2 | ([h] | [h; _]) |
| ÉS minta | minta1 & minta2 | (a, b) & (_, "test") |
| Mintázat hátrányai | azonosító :: listaazonosító | h :: t |
| Listaminta | [ pattern_1; ... ; pattern_n ] | [ a; b; c ] |
| Tömbminta | [| pattern_1; ..; pattern_n |] | [| a; b; c |] |
| Zárójeles minta | ( minta ) | ( a ) |
| Tupel minta | ( pattern_1, ... , pattern_n ) | ( a, b ) |
| Rekordminta | { azonosító1 = pattern_1; ... ; azonosító_n = pattern_n } | { Name = name; } |
| Helyettesítő karakterminta | _ | _ |
| Minta és szövegjegyzet | minta: típus | a : int |
| Típusteszt minta | :? típus [ azonosítóként ] | :? System.DateTime as dt |
| Null minta | null | null |
| Minta neve | az expr neve | nameof str |
Állandó minták
Az állandó minták numerikus, karakter- és sztringkonstansok, enumerálási állandók (az enumerálási típus nevével együtt). Egy match olyan kifejezés, amely csak állandó mintákkal rendelkezik, összehasonlítható más nyelveken található esetkimutatásokkal. A bemenet összehasonlítva van a literális értékkel, és a minta megegyezik, ha az értékek egyenlők. A literál típusának kompatibilisnek kell lennie a bemenet típusával.
Az alábbi példa a literális minták használatát mutatja be, és változó mintát és VAGY mintát is használ.
[<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
Egy másik példa a literális mintára az enumerálási állandókon alapuló minta. Enumerálási állandók használatakor meg kell adnia az enumerálási típus nevét.
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
Azonosítóminták
Ha a minta egy érvényes azonosítót alkotó karaktersorozat, az azonosító formája határozza meg a minta egyeztetését. Ha az azonosító hosszabb egy karakternél, és nagybetűvel kezdődik, a fordító megpróbál megegyezni az azonosító mintával. Ennek a mintának az azonosítója lehet a Literál attribútummal megjelölt érték, egy diszkriminált uniós eset, egy kivételazonosító vagy egy aktív mintaeset. Ha nem található egyező azonosító, az egyezés meghiúsul, és a következő mintaszabályt, a változómintát összehasonlítja a bemenettel.
A diszkriminált egyesítési minták lehetnek egyszerű elnevezett esetek, vagy rendelkezhetnek egy értékkel, esetleg egy többszörös értéket tartalmazó tuplával. Ha van érték, meg kell adnia az értékhez tartozó azonosítót. Tuple esetén meg kell adnia egy tupel mintát, amely azonosítót tartalmaz a tuple minden elemére, vagy egy azonosítót egy vagy több elnevezett uniómező mezőnevével. Példákért tekintse meg az ebben a szakaszban található kód példákat.
A option típus egy diszkriminált unió, amely két esetből áll, Some és None. Az egyik esetnek (Some) van értéke, a másik (None) azonban csak egy elnevezett eset. Ezért Some a Some-esethez társított érték változójával kell rendelkeznie, de a None önmagában kell megjelennie. Az alábbi kódban a var1 változó az Some-esetnek való megfeleléssel kapott értéket adja meg.
let printOption (data : int option) =
match data with
| Some var1 -> printfn "%d" var1
| None -> ()
A következő példában a PersonName diszkriminált egyesítés karakterláncok és karakterek keverékét tartalmazza, amelyek a nevek lehetséges formáit képviselik. A diszkriminált unió esetei a következők : FirstOnly, LastOnlyés 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
Az elnevezett mezőkkel rendelkező diszkriminált unióknál az egyenlőség jelével (=) lehet kinyerni egy elnevezett mező értékét. Vegyük például az alábbihoz hasonló deklarációval rendelkező diszkriminált uniót.
type Shape =
| Rectangle of height : float * width : float
| Circle of radius : float
A névvel ellátott mezőket az alábbiak szerint használhatja egy mintaegyező kifejezésben.
let matchShape shape =
match shape with
| Rectangle(height = h) -> printfn $"Rectangle with length %f{h}"
| Circle(r) -> printfn $"Circle with radius %f{r}"
A névvel ellátott mező használata nem kötelező, ezért az előző példában mind a Circle(r), mind a Circle(radius = r) ugyanaz a hatása.
Ha több mezőt ad meg, használja a pontosvesszőt (;) elválasztóként.
match shape with
| Rectangle(height = h; width = w) -> printfn $"Rectangle with height %f{h} and width %f{w}"
| _ -> ()
Az aktív minták lehetővé teszik összetettebb egyéni minták egyeztetését. Az aktív mintákról további információt az Aktív mintákcímű témakörben talál.
Az az eset, amikor az azonosító kivétel, a kivételkezelők kontextusában a mintaegyezésben használatos. A kivételkezelés mintaegyeztetéséről további információt Kivételek: A try...with Kifejezéscímű cikkben talál.
Változóminták
A változóminta egy változónévhez rendeli a megfeleltetendő értéket, amely a végrehajtási kifejezésben a -> szimbólumtól jobbra érhető el. A változóminta önmagában megfelel minden bemenetnek, de a változóminták gyakran más mintákban is megjelennek, így összetettebb struktúrák, például a csuplik és tömbök változókká bonthatók.
Az alábbi példa egy változómintát mutat be egy tömbmintán belül.
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)
mintaként
A as minta egy olyan minta, amelyhez hozzá van fűzve egy as záradék. A as záradék egy match kifejezés végrehajtási kifejezésében használható névhez köti a megfeleltethető értéket, vagy abban az esetben, ha ezt a mintát egy let kötésben használják, a név a helyi hatókörhöz kötésként lesz hozzáadva.
Az alábbi példa egy as mintát használ.
let (var1, var2) as tuple1 = (1, 2)
printfn "%d %d %A" var1 var2 tuple1
VAGY minta
Az OR mintát akkor használja a rendszer, ha a bemeneti adatok több mintával egyeznek, és ugyanazt a kódot szeretné végrehajtani az eredményként. Az OR mintázat mindkét oldalának típusának kompatibilisnek kell lennie.
Az alábbi példa az OR mintát mutatja be.
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)
ÉS minta
Az AND minta használatához a bemenetnek két mintával kell egyeznie. Az AND minta mindkét oldalának kompatibilisnek kell lennie.
Az alábbi példa hasonló ahhoz, amit a Kettős Minta szakaszban, később detectZeroTuple-ként bemutatunk, de itt var1 és var2 értékként kerülnek kinyerésre az ÉS minta használatával.
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)
Hátrányok mintázata
A „cons” minta egy lista felbontására szolgál, ahol az első elem a fej, és a többi elemet tartalmazó lista a farok.
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
Több hátránymintát is összefűzhet, hogy azok egyezzenek az adott elemsorozatokkal kezdődő listákkal.
let charList = ['A'; 'B'; 'C'; 'D']
// This example demonstrates multiple cons patterns.
let matchChars xs =
match xs with
| 'A'::'B'::t -> printfn "starts with 'AB', rest: %A" t
| 'A'::t -> printfn "starts with 'A', rest: %A" t
| 'C'::'D'::t -> printfn "starts with 'CD', rest: %A" t
| _ -> printfn "does not match"
matchChars charList
matchChars ['A'; 'X']
matchChars ['C'; 'D'; 'E']
Listaminta
A listaminta lehetővé teszi a listák több elemre bontását. Maga a listaminta csak bizonyos számú elem listáival egyezhet meg.
// 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 [ ] )
Elrendezési minta
A tömbminta hasonlít a listamintára, és egy adott hosszúságú tömbök felbontására használható.
// 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 [| |] )
Zárójeles minta
A zárójelek mintázatok köré csoportosíthatók a kívánt asszociativitás elérése érdekében. Az alábbi példában zárójelekkel szabályozható az AND-minta és a cons minta közötti asszociativitás.
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
Tubusminta
A rekordminta megfelel a bemenetnek a rekord formájában, és lehetővé teszi, hogy a rekordot alkotó elemekre bontsa. Ehhez használja a mintaegyező változókat a rekord minden egyes pozíciójához.
Az alábbi példa bemutatja a tuppel mintát, és literál mintákat, változó mintákat és helyettesítő mintát is használ.
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)
Rekord sablon
A rekordminta a rekordok felbontására szolgál a mezők értékeinek kinyeréséhez. A mintának nem kell a rekord összes mezőjére hivatkoznia; a kihagyott mezők csak nem vesznek részt az egyeztetésben, és nem nyerik ki őket.
// 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"
Helyettesítő karakterminta
A helyettesítő karaktermintát az aláhúzásjel (_) karakter jelöli, és a változómintához hasonlóan minden bemenetnek megfelel, azzal a kivétellel, hogy a bemenet elvetésre kerül, ahelyett, hogy egy változóhoz lenne hozzárendelve. A helyettesítő karaktereket gyakran más mintákban használják helyőrzőként az olyan értékekhez, amelyekre nincs szükség a -> szimbólumtól jobbra lévő kifejezésben. A helyettesítő karakterek mintáját gyakran használják a minták listájának végén, hogy megfeleljenek a nem egyező bemeneteknek. A helyettesítő karakterek mintáját a jelen témakör számos kód példájában szemlélteti. Egy példához lásd az előző kódot.
Az alábbi kód a helyettesítő karakterminta néhány további használatát mutatja be:
// Wildcard pattern matching "nothing" examples
// Example 1: Wildcard ignoring function parameters
let ignoreAllParams _ _ = "Ignores all input"
// Example 2: Wildcard in destructuring, ignoring elements
let getFirstOnly (first, _) = first
// Example 3: Using wildcard to ignore optional values
let handleEmpty opt =
match opt with
| Some _ -> "Has something"
| None -> "Has nothing"
// Usage
printfn "%s" (ignoreAllParams 42 "test")
printfn "%d" (getFirstOnly (1, "ignored"))
printfn "%s" (handleEmpty None)
Típusjegyzetekkel rendelkező minták
A minták típusjegyzetekkel is rendelkezhetnek. Ezek ugyanúgy viselkednek, mint más típus annotációk, és ugyanúgy segítik a következtetést, mint más típus annotációk. Zárójelekre van szükség a típusjegyzetek mintázataiban.
Egy típusjegyzetet tartalmazó minta a szintaxist pattern : type használja, és fordítási idő típusú információkat biztosít a típus-ellenőrzőnek. Ez pusztán egy statikus típusú széljegyzet, amely segít a típuskövetkezésben – nem végez futásidejű típusellenőrzést vagy átalakítást. A fordító ezeket az információkat használja a fordítás során a mintaváltozó típusának meghatározásához.
Az alábbi kód egy típusjegyzetet tartalmazó mintát mutat be:
let detect1 x =
match x with
| 1 -> printfn "Found a 1!"
| (var1 : int) -> printfn "%d" var1
detect1 0
detect1 1
Ebben a példában (var1 : int) a fordító var1 típusát intjelzi. Ez fordításkor oldódik fel, és a generált kód egész számként kezeli var1 az egyezés kifejezését. Ez a minta megfelel az összes egész szám értékének, és hozzá fogja kötni.var1
Főbb jellemzők:
- A szintaxist
pattern : typehasználja (egyetlen kettősponttal). - Fordításkor feloldva – típusinformációkat ad a típus ellenőrzőjének.
- Nem végez futásidejű típustesztelést.
- Típuskövetkeztetéshez és a fordító irányításához használható.
Típusteszt minta
A típustesztelési minta a bemenetnek a futtatókörnyezetben használt típussal való egyeztetésére szolgál. Ha a bemeneti típus megegyezik a mintában megadott típussal (vagy származtatott típussal), az egyezés sikeres lesz.
A típustesztelési minta a szintaxist :? type használja, és futásidejű típusellenőrzést végez, hasonlóan a is C# operátoraihoz as . Ez a minta azt ellenőrzi, hogy egy érték egy adott típusú-e a program végrehajtása során, így hasznos lehet az öröklési hierarchiák vagy a felület implementációinak használatakor.
Az alábbi példa a típustesztelési mintát mutatja be:
open System.Windows.Forms
let RegisterControl(control:Control) =
match control with
| :? Button as button -> button.Text <- "Registered."
| :? CheckBox as checkbox -> checkbox.Text <- "Registered."
| _ -> ()
Ha csak azt ellenőrzi, hogy egy azonosító egy adott származtatott típus-e, nem kell a minta as identifier része, ahogyan az alábbi példában látható:
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"
| _ -> ()
Főbb jellemzők:
- A szintaxist
:? typevagy:? type as identifier(kérdőjellel) használja. - Futásidőben feloldva – tényleges típusellenőrzést hajt végre a végrehajtás során.
- Ellenőrzi, hogy egy érték egy adott típus vagy annak származtatott típusainak példánya-e.
- Gyakran használják öröklési hierarchiák és polimorfikus típusok.
- Hasonló a C#operátorához vagy
asoperátoráhozis.
Kontrasztos típusjegyzetek és típustesztelési minták
Bár mindkét minta típusokat tartalmaz, nagyon különböző célokat szolgálnak:
| Tulajdonság | Írja be a széljegyzetmintát (pattern : type) |
Típusteszt minta (:? type) |
|---|---|---|
| Syntax | Egy kettőspont: a : int |
Kettőspont kérdőjellel: :? Button |
| Ha a probléma megoldódott | Fordítási idő | Runtime |
| Purpose | Segédvonalak típusának következtetése | Az érték tényleges típusának tesztelése |
| Használati eset | Segítség a fordítónak a típusok megértéséhez | Futtatókörnyezettípusok ellenőrzése öröklési hierarchiákban |
| Egyenértékű c nyelven# | Írjon be széljegyzeteket a kapcsolómintákba |
is vagy as operátorok |
Az alábbi példa a különbségeket mutatja be:
// Type annotation pattern - compile time
let detect1 x =
match x with
| 1 -> printfn "Found a 1!"
| (var1 : int) -> printfn "%d" var1
// The ': int' tells the compiler var1 is an int
// Everything is resolved at compile time
// Type test pattern - runtime
type A() = class end
type B() = inherit A()
let test (a: A) =
match a with
| :? B -> printfn "Runtime check: it's a B"
| _ -> printfn "Runtime check: it's not a B"
// The ':? B' performs a runtime type check
// The actual type is tested during execution
Null minta
A null minta megegyezik azzal a null értékkel, amely akkor jelenhet meg, ha null értéket engedélyező típusokkal dolgozik. A null mintákat gyakran használják a .NET-keretrendszer kódjával való együttműködéskor. A .NET API visszatérési értéke lehet például egy match kifejezés bemenete. A programfolyamatot attól függően szabályozhatja, hogy a visszatérési érték null-e, valamint a visszaadott érték egyéb jellemzői alapján is. A null mintával megakadályozhatja, hogy a null értékek a program többi részére propagáljanak.
Az alábbi példa a null mintát és a változómintát használja.
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()
Az F# 9 nullképességi képességek:
let len (str: string | null) =
match str with
| null -> -1
| s -> s.Length
Hasonlóképpen használhat új, dedikált nullbilitáshoz kapcsolódó mintákat:
let len str = // str is inferred to be `string | null`
match str with
| Null -> -1
| NonNull (s: string) -> s.Length
Minta neve
A nameof minta akkor egyezik egy sztringgel, ha értéke megegyezik a nameof kulcsszót követő kifejezéssel. Ez a minta különösen akkor hasznos, ha sztringértékeket kell egyeztetnie a típusok nevével, a diszkriminált egyesítési esetekkel vagy a kód más szimbólumaival. A használat nameof időtúllépési biztonságot nyújt, mert ha átnevez egy szimbólumot, a minta automatikusan az új nevet fogja használni.
Gyakori használati eset az adatok deszerializálása, ahol a sztringértékek típust vagy kis- és nagybetűket jelölnek:
type EventType =
| OrderCreated
| OrderShipped
| OrderDelivered
let handleEvent eventName data =
match eventName with
| nameof OrderCreated -> printfn "Processing order creation: %s" data
| nameof OrderShipped -> printfn "Processing order shipment: %s" data
| nameof OrderDelivered -> printfn "Processing order delivery: %s" data
| _ -> printfn "Unknown event type: %s" eventName
handleEvent "OrderCreated" "Order #123" // matches first case
handleEvent "OrderShipped" "Order #123" // matches second case
Ez a megközelítés jobb, mint a sztringkonstansok (például "OrderCreated") használata, mert:
- Ha átnevezi
OrderCreated,OrderPlaceda minta automatikusan frissül. - A fordító biztosítja a szimbólum meglétét, megakadályozva az elírásokat.
- A kód az újrabontáskor is konzisztens marad.
Paraméterekkel is használható nameof :
let f (str: string) =
match str with
| nameof str -> "It's 'str'!"
| _ -> "It is not 'str'!"
f "str" // matches
f "asdf" // does not match
Az nameof operátornál talál információt arról, hogy minek adhat nevet.