Sdílet prostřednictvím


Porovnávání vzorů (F#)

Vzorky jsou pravidla pro transformování vstupních dat.Používají se v celém jazyce F# k porovnání dat s logickou strukturou nebo strukturami, rozložení dat na základní prvky nebo extrahování informací z dat různými způsoby.

Poznámky

Vzorky se používají v mnoha konstrukcích jazyka, jako je výraz match.Používají se při zpracování argumentů pro funkce ve vazbách let, výrazech lambda a v obslužných rutinách výjimek spojených s výrazem try...with.Další informace naleznete v tématu Výrazy shody (F#), let – vazby (F#), Výrazy lambda: Klíčové slovo fun (F#) a Výjimky: Výraz try...with (F#).

Například ve výrazu match je pattern tím, co následuje symbol svislé čáry.

spojit expression s

| pattern [když condition ] –> result-expression

...

Každý vzorek se chová jako pravidlo pro transformování vstupu nějakým způsobem.U výrazu match je zkoumán každý vzorek, zda jsou vstupní data kompatibilní se vzorkem.Pokud je nalezena shoda, je výsledkem spuštění výrazu.Pokud není nalezena shoda, je testováno další pravidlo vzorku.Volitelně při vysvětlení části condition v Výrazy shody (F#).

Podporované vzory jsou uvedeny v následující tabulce.Při spuštění je vstup je testován oproti každému z následujících vzorů v pořadí uvedeném v tabulce, a vzory se používají rekurzivně, od prvního až poslední, tak jak se objevují ve vašem kódu a zleva doprava pro vzory na každém řádku.

Název

Description

Příklad

Konstantní vzorek

Všechny číselné, znakové nebo řetězcové literály, konstanta výčtu nebo definovaný identifikátor literálu

1.0, "test", 30, Color.Red

Vzorek identifikátoru

Hodnota case rozlišovaného sjednocení, popisku výjimky nebo aktivní hodnoty case vzoru

Some(x)

Failure(msg)

Vzorec proměnné

identifier

a

Vzor as

pattern jako identifier

(a, b) as tuple1

NEBO vzor

pattern1 | pattern2

([h] | [h; _])

Vzor AND

pattern1 & pattern2

(a, b) & (_, "test")

Nevýhody vzoru

identifier :: list-identifier

h :: t

Vzor seznamu

[ pattern_1; ... ; pattern_n ]

[ a; b; c ]

Vzor pole

[| pattern_1; ..; pattern_n ]

[| a; b; c |]

Vzor v závorce

( pattern )

( a )

Vzor řazené kolekce členů

( pattern_1, ... , pattern_n )

( a, b )

Vzor záznamu

{ identifier1 = pattern_1; ... ; identifier_n = pattern_n }

{ Name = name; }

Vzorec zástupných znaků

_

_

Vzorek společně s anotací typu

pattern : type

a : int

Testovací vzorek typu

:?type [ jako identifier ]

:? System.DateTime as dt

Vzor Null

null

null

Konstantní vzorky

Konstantní vzorky jsou čísla, znaky a řetězcové literály výčtu konstant (se zahrnutým názvem typu výčtu).Výraz match, který má pouze konstantní vzory, je možné porovnat s příkazy case v jiných jazycích.Vstup je porovnán s hodnotou literálu a pokud jsou hodnoty stejné, odpovídá vzoru.Typ literálu musí být kompatibilní s typem vstupu.

Následující příklad ukazuje použití vzorů literálu a také používá vzory proměnné a vzor 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

Dalším příkladem vzoru literálu je vzor založený na výčtu konstant.Při použití konstant výčtu musíte zadat název typu výčtu.

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

Vzorky identifikátoru

Pokud vzorek je řetězec znaků, který tvoří platný identifikátor, forma identifikátoru určuje, jak je vzorek párován.Pokud identifikátor je delší než jeden znak a začíná velkým písmenem, kompilátor se pokusí spárovat se vzorkem identifikátoru.Identifikátor pro tento vzorek může být hodnota označená jako literální atribut, případ diskriminovaného sjednocení, identifikátor výjimky nebo případ aktivního vzoru.Pokud není nalezen žádný odpovídající identifikátor, shoda se nezdaří a další pravidlo pro vzorek, vzorek proměnné, se porovná se vstupem.

Vzorky rozlišeného sjednocení mohou být jednoduše pojmenované případy nebo mohou mít hodnotu či n-tici obsahující více hodnot.Pokud existuje hodnota, musíte zadat identifikátor pro hodnotu.V případě n-tice musíte zadat vzor n-tice s identifikátorem pro každý element n-tice nebo identifikátor s názvem pole pro jedno nebo více sjednocených polí.Příklady kódu naleznete v této části s příklady.

Typ option představuje diskriminované sjednocení, které má dva případy - Some a None.Jeden případ (Some) má hodnotu, ale další (None) je pouze pojmenovaný případ.Proto musí mít Some proměnnou pro hodnotu spojenou s případem Some, ale None se musí zobrazovat samostatně.V následujícím kódu je proměnné var1 přiřazena hodnota získaná pomocí odpovídajícího případu Some.

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

V následujícím příkladu diskriminovaná unie PersonName obsahuje směs řetězců a znaků, které představují možné formy jména.Případy diskriminovaného sjednocení jsou FirstOnly, LastOnly a 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

Pro rozlišovaná sjednocení, která mají pojmenované názvy polí, použijte znaménko rovnítko (=) k získání hodnoty pojmenovaného pole.Zvažte například diskriminované sjednocení s deklarací, jako je následující.

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

Pojmenovaná pole můžete použít ve výrazu odpovídajícímu vzorci následujícím způsobem.

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

Použití pojmenovaného pole je volitelné, protože v předchozím příkladu má Circle(r) a Circle(radius = r) stejný efekt.

Pokud zadáte více polí, použijte středník (;) jako oddělovač.

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

Aktivní vzorky umožňují definovat složitější vlastní porovnávání vzorků.Další informace o aktivních vzorech naleznete v části Aktivní vzorky (F#).

Případ, ve kterém je identifikátor výjimkou, se používá pro porovnávání se vzory v kontextu obslužných rutin výjimek.Informace o vzoru porovnávání ve zpracování výjimek naleznete v tématu Výjimky: Výraz try...with (F#).

Vzorce proměnné

Variabilní vzor přiřadí hodnotu porovnávanou s názvem proměnné, která je pak k dispozici pro použití v prováděném výrazu vpravo od symbolu ->.Variabilní vzor odpovídá jakémukoliv vstupu, ale variabilní vzorky se často objevuje v rámci jiných vzorků, proto umožňuje složitější struktury, jako například záznamy a pole, které lze rozložit na proměnné.

Následující příklad ukazuje vzor proměnné v rámci vzoru n-tice.

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 Vzor

Vzor as je vzorkem, ke kterému je připojena klauzule as.Klauzule as váže odpovídající hodnotu k názvu, který lze použít při definici spuštění výrazu match, nebo v případě použití tohoto vzoru ve vazbě let pro přidání názvu jako vazby v místním rozsahu.

V následujícím příkladu je použit vzor as.

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

NEBO vzor

Vzor OR se používá, když vstupní data mohou odpovídat více vzorům a chcete provést ve výsledku stejný kód.Typy obou stran vzoru operátoru OR musí být kompatibilní.

Následující příklad demonstruje vzory 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)

Vzor AND

Vzor AND vyžaduje, aby byla na vstupu shoda dvou vzorků.Typy obou stran vzoru operátoru AND musí být kompatibilní.

Následující příklad je podobný detectZeroTuple uvedeného v části Vzor n-tice dále v tomto tématu, ale zde jsou var1 a var2 získány jako hodnoty pomocí vzoru 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)

Nevýhody vzoru

Vzorek nevýhod se používá rozložení seznamu na první prvek, záhlaví a seznam, který obsahuje zbývající prvky – zakončení.

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

Vzor seznamu

Vzor seznamu umožňuje rozložit seznamy na prvky.Vzor seznamu sám může odpovídat pouze seznamům určitého počtu prvků.

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

Vzor pole

Vzorec pole se podobá vzoru seznamu a lze jej použít k rozložení polí určité délky.

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

Vzor v závorce

Závorky mohou být seskupeny kolem vzorků k dosažení požadované asociativity.V následujícím příkladu jsou použity závorky pro řízení asociativity mezi vzorcem AND a vzorcem nevýhod.

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

Vzor řazené kolekce členů

Vzorec řazené kolekce členů odpovídá formě řazené kolekce členů a umožňuje její rozložení na základní prvky pomocí proměnných porovnání vzorce pro každou pozici v řazené kolekci členů.

Následující příklad ukazuje vzor n-tice a také používá vzor literálu, vzory proměnné a vzor zástupných znaků.

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)

Vzor záznamu

Vzor záznamu slouží k rozložení záznamů a následné extrahování hodnot polí.Vzor neobsahuje odkaz na všechna pole záznamu. Vynechaná pole pouze nejsou součástí srovnávání a nejsou extrahována.

// 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"

Vzorec zástupných znaků

Vzorec zástupných znaků je vyjádřen podtržítkem (_) a odpovídá jakémukoli zadání, stejně jako vzorec proměnné s tou výjimkou, že je vstup ignorován místo toho, aby byl přiřazen proměnné.Maska zástupných znaků se často používá v rámci jiných vzorků jako zástupný symbol pro hodnoty, které nejsou potřeba ve výrazu vpravo od symbolu ->.Vzorec zástupných znaků se také často používá na konci seznamu vzorků tak, aby odpovídal jakémukoli neodpovídajícímu vstupu.Maska zástupných znaků je znázorněna v mnoha příkladech kódu v tomto tématu.Příklad viz předchozí kód.

Vzorky, které mají anotace typu

Vzorky mohou mít anotace typu.Chovají se jako ostatní poznámky typu a příručka pro odvození stejně jako ostatní poznámky typu.Jsou vyžadovány závorky kolem anotace typu ve vzorcích.Následující kód popisuje vzor, který má anotaci typu.

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

Testovací vzorek typu

Vzor testovacího typu slouží k porovnání vstupu oproti typu.Pokud je vstupní typ porovnán s (nebo odvozeným typem) typem určeným ve vzorku, porovnávání je úspěšné.

Následující příklad demonstruje vzor testu typu.

open System.Windows.Forms

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

Vzor Null

Vzor Null odpovídá hodnotě null, která se ,může zobrazit při práci s typy, které umožňují hodnotu null.Vzory Null jsou často používány při spolupráci s kódem .NET Framework.Například hodnota vrácená pomocí .NET API může být vstup do výrazu match.Můžete řídit tok programu na základě toho, zda je vrácená hodnota null a také na jiných vlastnostech vrácené hodnoty.Vzorec hodnot null můžete použít k zabránění šíření hodnot null do ostatních částí programu.

Následující příklad používá vzor null a vzor proměnné.

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

Viz také

Referenční dokumentace

Výrazy shody (F#)

Aktivní vzorky (F#)

Další zdroje

Referenční dokumentace jazyka F#