Criteri di ricerca
I modelli sono regole per la trasformazione dei dati di input. Vengono usati in F# per confrontare i dati con una struttura logica o strutture, scomporre i dati in parti costitutive o estrarre informazioni dai dati in diversi modi.
Osservazioni:
I modelli vengono usati in molti costrutti di linguaggio, ad esempio l'espressione match
. Vengono usati quando si elaborano argomenti per le funzioni nelle let
associazioni, nelle espressioni lambda e nei gestori di eccezioni associati all'espressione try...with
. Per altre informazioni, vedere Espressioni di corrispondenza, let Bindings, Lambda Expressions: The fun
Keyword, and Exceptions: The try...with
Expression.
Nell'espressione match
, ad esempio, il criterio segue il simbolo della pipe.
match expression with
| pattern [ when condition ] -> result-expression
...
Ogni modello funge da regola per trasformare l'input in qualche modo. Nell'espressione match
, ogni criterio viene esaminato a sua volta per verificare se i dati di input sono compatibili con il modello. Se viene trovata una corrispondenza, viene eseguita l'espressione del risultato. Se non viene trovata una corrispondenza, viene testata la regola del modello successiva. La parte facoltativa quando la condizione è illustrata in Espressioni di corrispondenza.
I modelli supportati sono illustrati nella tabella seguente. In fase di esecuzione, l'input viene testato in base a ognuno dei modelli seguenti nell'ordine elencato nella tabella e i modelli vengono applicati in modo ricorsivo, dal primo all'ultimo come appaiono nel codice e da sinistra a destra per i modelli in ogni riga.
Nome | Descrizione | Esempio |
---|---|---|
Criterio costante | Qualsiasi valore letterale numerico, carattere o stringa, costante di enumerazione o identificatore letterale definito | 1.0 , "test" , 30 Color.Red |
Modello di identificatore | Valore case di un'unione discriminata, un'etichetta di eccezione o un caso di modello attivo | Some(x) Failure(msg) |
Modello di variabile | identificatore | a |
Criterio as |
pattern come identificatore | (a, b) as tuple1 |
Modello OR | pattern1 | pattern2 | ([h] | [h; _]) |
Modello AND | pattern1 & pattern2 | (a, b) & (_, "test") |
Modello cons | identificatore :: list-identifier | h :: t |
Modello elenco | [ pattern_1; ... ; pattern_n ] | [ a; b; c ] |
Modello di matrice | [| pattern_1; ..; pattern_n |] | [| a; b; c |] |
Criterio tra parentesi | ( pattern ) | ( a ) |
Modello di tupla | ( pattern_1, ... , pattern_n ) | ( a, b ) |
Modello di record | { identifier1 = pattern_1; ... ; = identifier_n pattern_n } | { Name = name; } |
Modello con caratteri jolly | _ | _ |
Pattern insieme all'annotazione del tipo | pattern : tipo | a : int |
Modello di test dei tipi | :? type [ as identifier ] | :? System.DateTime as dt |
Modello Null | Null | null |
Modello Nameof | nameof expr | nameof str |
Modelli costanti
I modelli costanti sono valori letterali numerici, carattere e stringa, costanti di enumerazione (con il nome del tipo di enumerazione incluso). Un'espressione match
con solo modelli costanti può essere confrontata con un'istruzione case in altri linguaggi. L'input viene confrontato con il valore letterale e il criterio corrisponde se i valori sono uguali. Il tipo di valore letterale deve essere compatibile con il tipo di input.
L'esempio seguente illustra l'uso di modelli letterali e usa anche un modello di variabile e un modello 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
Un altro esempio di modello letterale è un modello basato sulle costanti di enumerazione. È necessario specificare il nome del tipo di enumerazione quando si utilizzano costanti di enumerazione.
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
Modelli di identificatore
Se il criterio è una stringa di caratteri che forma un identificatore valido, il formato dell'identificatore determina la corrispondenza del criterio. Se l'identificatore è più lungo di un singolo carattere e inizia con un carattere maiuscolo, il compilatore tenta di trovare una corrispondenza con il modello di identificatore. L'identificatore di questo modello può essere un valore contrassegnato con l'attributo Literal, un caso di unione discriminante, un identificatore di eccezione o un caso di criterio attivo. Se non viene trovato alcun identificatore corrispondente, la corrispondenza ha esito negativo e la regola del modello successiva, il modello di variabile, viene confrontato con l'input.
I modelli di unione discriminati possono essere semplici case denominati oppure avere un valore o una tupla contenente più valori. Se è presente un valore, è necessario specificare un identificatore per il valore. Nel caso di una tupla, è necessario fornire un modello di tupla con un identificatore per ogni elemento della tupla o un identificatore con un nome di campo per uno o più campi unione denominati. Per esempi, vedere gli esempi di codice in questa sezione.
Il option
tipo è un'unione discriminata con due casi, Some
e None
. Un caso (Some
) ha un valore, ma l'altro (None
) è solo una maiuscola denominata. Pertanto, Some
deve avere una variabile per il valore associato al Some
case, ma None
deve essere visualizzata da sola. Nel codice seguente, alla variabile var1
viene assegnato il valore ottenuto eseguendo la corrispondenza con il Some
case.
let printOption (data : int option) =
match data with
| Some var1 -> printfn "%d" var1
| None -> ()
Nell'esempio seguente l'unione PersonName
discriminata contiene una combinazione di stringhe e caratteri che rappresentano possibili forme di nomi. I casi dell'unione discriminata sono FirstOnly
, LastOnly
e 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
Per le unioni discriminate con campi denominati, usare il segno di uguale (=) per estrarre il valore di un campo denominato. Si consideri, ad esempio, un'unione discriminata con una dichiarazione simile alla seguente.
type Shape =
| Rectangle of height : float * width : float
| Circle of radius : float
È possibile usare i campi denominati in un'espressione di ricerca di criteri come indicato di seguito.
let matchShape shape =
match shape with
| Rectangle(height = h) -> printfn $"Rectangle with length %f{h}"
| Circle(r) -> printfn $"Circle with radius %f{r}"
L'uso del campo denominato è facoltativo, quindi nell'esempio precedente, entrambi Circle(r)
e Circle(radius = r)
hanno lo stesso effetto.
Quando si specificano più campi, usare il punto e virgola (;) come separatore.
match shape with
| Rectangle(height = h; width = w) -> printfn $"Rectangle with height %f{h} and width %f{w}"
| _ -> ()
I modelli attivi consentono di definire criteri personalizzati più complessi. Per altre informazioni sui modelli attivi, vedere Modelli attivi.
Il caso in cui l'identificatore è un'eccezione viene usato nei criteri di ricerca nel contesto dei gestori di eccezioni. Per informazioni sui criteri di ricerca nella gestione delle eccezioni, vedere Eccezioni: Espressionetry...with
.
Modelli di variabile
Il criterio di variabile assegna il valore corrispondente a un nome di variabile, che è quindi disponibile per l'uso nell'espressione di esecuzione a destra del ->
simbolo. Un modello di variabile corrisponde da solo a qualsiasi input, ma i modelli di variabile vengono spesso visualizzati all'interno di altri modelli, consentendo quindi strutture più complesse, ad esempio tuple e matrici, di essere scomposte in variabili.
Nell'esempio seguente viene illustrato un modello di variabile all'interno di un modello di tupla.
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)
come modello
Il as
criterio è un criterio con una as
clausola aggiunta. La as
clausola associa il valore corrispondente a un nome che può essere utilizzato nell'espressione di esecuzione di un'espressione match
oppure, nel caso in cui questo modello venga usato in un'associazione let
, il nome viene aggiunto come associazione all'ambito locale.
Nell'esempio seguente viene utilizzato un as
modello .
let (var1, var2) as tuple1 = (1, 2)
printfn "%d %d %A" var1 var2 tuple1
Modello OR
Il modello OR viene usato quando i dati di input possono corrispondere a più modelli e si vuole eseguire lo stesso codice di conseguenza. I tipi di entrambi i lati del modello OR devono essere compatibili.
Nell'esempio seguente viene illustrato il modello 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)
Modello AND
Il modello AND richiede che l'input corrisponda a due modelli. I tipi di entrambi i lati del modello AND devono essere compatibili.
L'esempio seguente è simile detectZeroTuple
a quello illustrato nella sezione Modello di tupla più avanti in questo argomento, ma in questo caso entrambi var1
e var2
vengono ottenuti come valori usando il modello 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)
Modello cons
Il modello cons viene usato per scomporre un elenco nel primo elemento, nella testa e in un elenco che contiene gli elementi rimanenti, la coda.
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
Modello elenco
Il modello di elenco consente di scomporre gli elenchi in un numero di elementi. Il modello di elenco stesso può corrispondere solo agli elenchi di un numero specifico di elementi.
// 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 [ ] )
Modello di matrice
Il modello di matrice è simile al modello di elenco e può essere usato per scomporre le matrici di una lunghezza specifica.
// 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 [| |] )
Modello racchiuso tra parentesi
Le parentesi possono essere raggruppate intorno ai modelli per ottenere l'associatività desiderata. Nell'esempio seguente, le parentesi vengono usate per controllare l'associatività tra un modello AND e un modello 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
Modello di tupla
Il modello di tupla corrisponde all'input nel formato tupla e consente di scomporre la tupla nei relativi elementi costitutivi usando variabili di corrispondenza dei criteri per ogni posizione nella tupla.
Nell'esempio seguente viene illustrato il modello di tupla e vengono usati anche modelli letterali, modelli di variabili e il modello con caratteri jolly.
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)
Modello di record
Il modello di record viene usato per scomporre i record per estrarre i valori dei campi. Il modello non deve fare riferimento a tutti i campi del record; i campi omessi non partecipano solo alla corrispondenza e non vengono estratti.
// 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"
Modello con caratteri jolly
Il modello con caratteri jolly è rappresentato dal carattere di sottolineatura (_
) e corrisponde a qualsiasi input, proprio come il modello di variabile, ad eccezione del fatto che l'input viene eliminato anziché assegnato a una variabile. Il criterio con caratteri jolly viene spesso usato all'interno di altri modelli come segnaposto per i valori non necessari nell'espressione a destra del ->
simbolo. Il criterio con caratteri jolly viene spesso usato anche alla fine di un elenco di modelli per trovare una corrispondenza con qualsiasi input non corrispondente. Il modello con caratteri jolly è illustrato in molti esempi di codice in questo argomento. Per un esempio, vedere il codice precedente.
Modelli con annotazioni di tipo
I modelli possono avere annotazioni di tipo. Questi si comportano come altre annotazioni di tipo e inferenza guida come altre annotazioni di tipo. Le parentesi sono necessarie intorno alle annotazioni dei tipi nei modelli. Il codice seguente illustra un modello con un'annotazione di tipo.
let detect1 x =
match x with
| 1 -> printfn "Found a 1!"
| (var1 : int) -> printfn "%d" var1
detect1 0
detect1 1
Modello di test dei tipi
Il modello di test del tipo viene usato per trovare la corrispondenza tra l'input e un tipo. Se il tipo di input è una corrispondenza con (o un tipo derivato di ) il tipo specificato nel criterio, la corrispondenza ha esito positivo.
Nell'esempio seguente viene illustrato il modello di test del tipo.
open System.Windows.Forms
let RegisterControl(control:Control) =
match control with
| :? Button as button -> button.Text <- "Registered."
| :? CheckBox as checkbox -> checkbox.Text <- "Registered."
| _ -> ()
Se si controlla solo se un identificatore è di un particolare tipo derivato, non è necessaria la as identifier
parte del modello, come illustrato nell'esempio seguente:
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"
| _ -> ()
Modello Null
Il criterio Null corrisponde al valore Null che può essere visualizzato quando si utilizzano tipi che consentono un valore Null. I modelli Null vengono spesso usati durante l'interoperabilità con il codice .NET Framework. Ad esempio, il valore restituito di un'API .NET potrebbe essere l'input di un'espressione match
. È possibile controllare il flusso del programma in base all'eventuale valore restituito null e anche ad altre caratteristiche del valore restituito. È possibile usare il modello Null per impedire la propagazione dei valori Null al resto del programma.
Nell'esempio seguente vengono usati il criterio Null e il modello di variabile.
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()
Modello Nameof
Il nameof
criterio corrisponde a una stringa quando il relativo valore è uguale all'espressione che segue la nameof
parola chiave . ad esempio:
let f (str: string) =
match str with
| nameof str -> "It's 'str'!"
| _ -> "It is not 'str'!"
f "str" // matches
f "asdf" // does not match
Vedere l'operatore nameof
per informazioni su ciò che è possibile accettare un nome.