Megosztás a következőn keresztül:


Mintaegyezés

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", 30, Color.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 nulla 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

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.

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. 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

Típusteszt minta

A típustesztelési minta a bemenet 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.

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"
    | _ -> ()

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 let 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. például:

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.

Lásd még: