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ákat számos nyelvi szerkezetben használják, például a kifejezésben match . Ezek akkor használatosak, ha a kötésekben, lambdakifejezésekben és a kifejezéshez try...with társított kivételkezelőkben lévő függvények let argumentumait dolgozza fel. További információt a Kifejezések egyeztetése, a Kötések, a Lambda-kifejezések: a fun kulcsszó és a kivételek: A try...with kifejezés című témakörben talál.

A kifejezésben például a matchminta a cső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 kifejezésben a match rendszer minden mintát megvizsgál annak ellenőrzésére, 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. Nem kötelező, ha a feltétel rész magyarázata a Kifejezések egyeztetése című témakörben található.

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ó, kivételcímke vagy aktív minta esetértéke Some(x)

Failure(msg)
Változó minta Azonosító a
as Minta minta azonosítóként (a, b) as tuple1
VAGY minta pattern1 | pattern2 ([h] | [h; _])
ÉS minta pattern1 > pattern2 (a, b) & (_, "test")
Hátrányok minta azonosító :: list-identifier 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 )
Rekordminta ( pattern_1, ... , pattern_n ) ( a, b )
Rekordminta { identifier1 = pattern_1; ... ; = identifier_n pattern_n } { Name = name; }
Helyettesítő karakterminta _ _
Minta és szövegjegyzet minta : típus a : int
Típusteszt minta :? type [ as identifier ] :? System.DateTime as dt
Null minta null null
Minta neve expr név 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, más nyelveken is összehasonlítható egy esetkimutatással. 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 lehetnek értékük vagy több értéket tartalmazó rekordjuk. Ha van érték, meg kell adnia az érték azonosítót. Tuple esetén meg kell adnia egy rekordmintát a rekord egyes elemeihez tartozó azonosítóval, vagy egy azonosítót egy vagy több elnevezett egyesítő 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ó, amelynek két esete van, Some és None. Az egyik eset (Some) értéke van, a másik (None) azonban csak egy elnevezett eset. Some Ezért rendelkeznie kell egy változóval az esethez Some társított értékhez, de None önmagában kell megjelennie. A következő kódban a változó var1 az esethez Some való egyezteté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 sztringek és karakterek keverékét tartalmazza, amelyek a nevek lehetséges formáit jelölik. 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 egyesítők esetében az egyenlőségjel (=) használatával nyerheti ki 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 mindkettő Circle(r)Circle(radius = r) ugyanazzal a hatással bír.

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ák cí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 a Kivételek: A try...with kifejezés című témakörben 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 -> használható. 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 rekordmintá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 egy as záradék van hozzáfűzve. A as záradék a megfeleltetett értéket egy kifejezés végrehajtási kifejezésében használható névhez köti match , vagy abban az esetben, ha ezt a mintát egy kötésben let 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 minta mindkét oldalá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 a jelen témakör későbbi, Tuple Pattern szakaszában láthatóhoz hasonlódetectZeroTuple, de itt mindkettőt var2var1 értékként kapjuk meg az AND 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 minta

A cons minta a lista első elemére, a fejre és a fennmaradó elemeket, a farkát tartalmazó listára bontható.

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 [ ] )

Tömbminta

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

Rekordminta

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 rekordmintát, és konstans mintákat, változó mintákat és helyettesítő karaktereket 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)

Rekordminta

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ő karaktert 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 nem változóhoz van rendelve. A helyettesítő karaktermintát gyakran más mintákban használják helyőrzőként a szimbólumtól jobbra -> lévő kifejezésben nem szükséges értékekhez. 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 úgy viselkednek, mint más típusú széljegyzetek és útmutató következtetés, mint más típusú széljegyzetek. 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, nincs szüksége a as identifier minta egy részére, ahogyan az 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 .NET-keretrendszer kóddal való együttműködéskor. Egy .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()

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

A névvel kapcsolatos információkért tekintse meg az nameof operátort.

Lásd még