Partage via


Critères spéciaux

Les modèles sont des règles pour transformer les données d’entrée. Ils sont utilisés en F# pour comparer des données avec une ou des structures logiques, décomposer les données en parties constituantes ou extraire des informations des données de plusieurs manières.

Notes

Les modèles sont utilisés dans de nombreuses constructions de langage, telles que l’expression match. Ils sont utilisés lorsque vous traitez des arguments pour les fonctions dans les liaisons let les expressions lambda et dans les gestionnaires d’exceptions associés à l’expression try...with . Pour plus d’informations, consultez Correspondance d’expressions, Liaisons Let, Expressions lambda : le funmot clé et Exceptions : l’try...withexpression.

Par exemple, dans l’expression match, le modèle correspond à ce qui suit le symbole de canal.

match expression with
| pattern [ when condition ] -> result-expression
...

Chaque modèle agit comme règle pour transformer l’entrée d’une manière ou d’une autre. Dans l’expression match, chaque modèle est examiné à son tour pour voir si les données d’entrée sont compatibles avec le modèle. Si une correspondance est trouvée, l’expression de résultat est exécutée. Si une correspondance n’a pas pu être trouvée, la règle de modèle suivante est testée. Le composant facultatif lorsque la condition est expliquée dans Expressions de correspondance.

Les modèles pris en charge sont indiqués dans le tableau suivant. Au moment de l’exécution, l’entrée est testée par rapport à chacun des modèles suivants dans l’ordre indiqué dans le tableau, et les modèles sont appliqués de manière récursive, du premier au dernier à mesure qu’ils apparaissent dans votre code, et de gauche à droite pour les modèles sur chaque ligne.

Nom Description Exemple
Modèle de constante Un littéral numérique, de caractère ou de chaîne, une constante d’énumération ou un identificateur littéral défini 1.0, "test", 30, Color.Red
Modèle d’identificateur Valeur de cas d’une union discriminée, d’une étiquette d’exception ou d’un cas de modèle actif Some(x)

Failure(msg)
Modèle de variable identifier a
as motif modèle en tant qu’identificateur (a, b) as tuple1
Modèle OR pattern1 | pattern2 ([h] | [h; _])
Modèle AND pattern1 et pattern2 (a, b) & (_, "test")
Modèle Cons identifier :: list-identifier h :: t
Modèle de liste [ pattern_1; ... ; pattern_n ] [ a; b; c ]
Modèle de tableau [| pattern_1; ..; pattern_n |] [| a; b; c |]
Modèle entre parenthèses ( pattern ) ( a )
Motif tuple ( pattern_1, ... , pattern_n ) ( a, b )
Modèle d’enregistrement { identifier1 = pattern_1; ... ; identifier_n = pattern_n } { Name = name; }
Modèle de caractère générique _ _
Modèle avec annotation de type pattern : type a : int
Modèle de test de type :? type [ as identifier ] :? System.DateTime as dt
Modèle Null null null
Modèle Nameof nameof expr nameof str

Modèles de constante

Les modèles de constante sont des littéraux numériques, de caractère et de chaîne, des constantes d’énumération (avec le nom du type d’énumération inclus). Une expression match qui n’a que des modèles de constante peut être comparée à une instruction Case dans d’autres langages. L’entrée est comparée à la valeur littérale et le modèle correspond si les valeurs sont égales. Le type du littéral doit être compatible avec le type de l’entrée.

L’exemple suivant illustre l’utilisation de modèles littéraux et utilise également un modèle de variable et un modèle 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 autre exemple de modèle de littéral est un modèle basé sur des constantes d’énumération. Vous devez spécifier le nom du type d’énumération lorsque vous utilisez des constantes d’énumération.

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

Modèles d’identificateur

Si le modèle est une chaîne de caractères qui forme un identificateur valide, la forme de l’identificateur détermine la façon dont le modèle est mis en correspondance. Si l’identificateur est plus long qu’un seul caractère et commence par un caractère en majuscule, le compilateur tente de faire correspondre le modèle d’identificateur. L’identificateur de ce modèle peut être une valeur marquée avec l’attribut de type littéral, un cas d’union discriminé, un identificateur d’exception ou un cas de modèle actif. Si aucun identificateur correspondant n’est trouvé, la correspondance échoue et la règle de modèle suivante, le modèle de variable, est comparée à l’entrée.

Les modèles d’union discriminés peuvent être de simples cas nommés ou avoir une valeur ou un tuple contenant plusieurs valeurs. S’il existe une valeur, vous devez indiquer un identificateur pour la valeur. Dans le cas d’un tuple, vous devez fournir un modèle de tuple avec un identificateur pour chaque élément du tuple ou un identificateur avec un nom de champ pour un ou plusieurs champs d’union nommés. Pour obtenir des exemples, consultez les exemples de code de cette section.

Le type option est une union discriminée qui a deux cas, Some et None. Un cas (Some) a une valeur, mais l’autre (None) est simplement un cas nommé. Par conséquent, Some doit avoir une variable pour la valeur associée au cas Some, mais le cas None doit apparaître de lui-même. Dans le code suivant, la variable var1 reçoit la valeur obtenue au moyen de la correspondance avec le cas Some.

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

Dans l’exemple suivant, l’union discriminée PersonName contient un mélange de chaînes et de caractères qui représentent des formes possibles de noms. Les cas de l’union discriminée sont FirstOnly, LastOnly et 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

Pour les unions discriminées qui ont des champs nommés, vous utilisez le signe égal (=) pour extraire la valeur d’un champ nommé. Par exemple, considérez une union discriminée avec une déclaration comme celle-ci.

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

Vous pouvez utiliser les champs nommés dans une expression de correspondance de critères spéciaux comme suit.

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

L’utilisation du champ nommé étant facultative, dans l’exemple précédent, Circle(r) et Circle(radius = r) ont le même effet.

Lorsque vous spécifiez plusieurs champs, utilisez le point-virgule (;) en tant que séparateur.

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

Les modèles actifs vous permettent de définir des critères spéciaux personnalisés plus complexes. Pour plus d’informations sur les modèles actifs, consultez les Modèles actifs.

Le cas dans lequel l’identificateur est une exception est utilisé dans les critères spéciaux dans le contexte des gestionnaires d’exceptions. Pour plus d’informations sur les critères spéciaux dans la gestion des exceptions, consultez Exceptions : l’expression try...with.

Modèles de variables

Le modèle de variable affecte la valeur mise en correspondance à un nom de variable, qui est ensuite disponible pour une utilisation dans l’expression d’exécution à droite du symbole ->. Un modèle de variable seul correspond à n’importe quelle entrée, mais les modèles de variables apparaissent souvent dans d’autres modèles, ce qui permet d’activer des structures plus complexes telles que les tuples et les tableaux à décomposer en variables.

L’exemple suivant illustre un modèle de variable dans un modèle de tuple.

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)

en tant que modèle

Le modèle as est un modèle auquel une clause as est ajoutée. La clause as lie la valeur mise en correspondance à un nom qui peut être utilisé dans l’expression d’exécution d’une expression match ou, lorsque ce modèle est utilisé dans une liaison let, le nom est ajouté en tant que liaison à la portée locale.

L’exemple suivant utilise un modèle as.

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

Modèle OR

Le modèle OR est utilisé lorsque les données d’entrée peuvent correspondre à plusieurs modèles et que vous souhaitez exécuter le même code. Les types des deux côtés du modèle OR doivent être compatibles.

L’exemple suivant illustre le modèle 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)

Modèle AND

Le modèle AND nécessite que l’entrée corresponde à deux modèles. Les types des deux côtés du modèle AND doivent être compatibles.

L’exemple suivant est semblable à detectZeroTuple, présenté dans la section Modèle de tuple plus loin dans cette rubrique, mais ici, var1 et var2 sont obtenus en tant que valeurs à l’aide du modèle 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)

Modèle Cons

Le modèle Cons est utilisé pour décomposer une liste en un premier élément, le début, et une liste qui contient les éléments restants, la fin.

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

Modèle de liste

Le modèle de liste permet de décomposer les listes en un certain nombre d’éléments. Le modèle de liste lui-même peut correspondre uniquement à des listes d’un nombre spécifique d’éléments.

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

Modèle de tableau

Le modèle de tableau ressemble au modèle de liste et peut être utilisé pour décomposer des tableaux d’une longueur spécifique.

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

Modèle entre parenthèses

Les parenthèses peuvent être regroupées autour de modèles pour obtenir l’associativité souhaitée. Dans l’exemple suivant, les parenthèses sont utilisées pour contrôler l’association entre un modèle AND et un modèle 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

Modèle de tuple

Le modèle de tuple correspond à l’entrée sous forme de tuple et permet de décomposer le tuple en ses éléments constitutifs à l’aide de variables de critères spéciaux pour chaque position dans le tuple.

L’exemple suivant illustre le modèle de tuple et utilise également des modèles de littéraux, des modèles de variables et le modèle de caractère générique.

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)

Modèle d’enregistrement

Le modèle d’enregistrement est utilisé pour décomposer les enregistrements afin d’extraire les valeurs des champs. Le modèle n’a pas besoin de référencer tous les champs de l’enregistrement ; tous les champs omis ne participent pas à la correspondance et ne sont pas extraits.

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

Modèle de caractère générique

Le modèle de caractère générique est représenté par le trait de soulignement (_) et correspond à n’importe quelle entrée, tout comme le modèle de variable, sauf que l’entrée est ignorée au lieu d’être affectée à une variable. Le modèle de caractère générique est souvent utilisé dans d’autres modèles comme espace réservé pour les valeurs qui ne sont pas nécessaires dans l’expression à droite du symbole ->. Le modèle de caractère générique est également fréquemment utilisé à la fin d’une liste de modèles pour correspondre à toute entrée sans correspondance. Le modèle de caractère générique est illustré dans de nombreux exemples de code de cette rubrique. Consultez le code précédent pour obtenir un exemple.

Modèles qui ont des annotations de type

Les modèles peuvent avoir des annotations de type. Ils se comportent comme d’autres annotations de type et guident l’inférence comme d’autres annotations de type. Les parenthèses sont requises autour des annotations de type dans les modèles. Le code suivant montre un modèle qui a une annotation de type.

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

Modèle de test de type

Le modèle de test de type est utilisé pour faire correspondre l’entrée à un type. Si le type d’entrée est une correspondance à un type spécifié (ou à un type dérivé de ce type) dans le modèle, la correspondance réussit.

L’exemple suivant illustre le modèle de test de type.

open System.Windows.Forms

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

Si vous vérifiez uniquement qu’un identificateur est d’un type dérivé particulier, vous n’avez pas besoin de la partie as identifier du modèle, comme illustré dans l’exemple suivant :

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

Modèle Null

Le modèle Null correspond à la valeur Null qui peut apparaître lorsque vous travaillez avec des types qui autorisent une valeur Null. Les modèles Null sont fréquemment utilisés lors de l’interopérabilité avec le code .NET Framework. Par exemple, la valeur renvoyée d’une API .NET peut être l’entrée d’une expression match. Vous pouvez contrôler le flux du programme en fonction de la valeur renvoyée (Null ou non Null) et d’autres caractéristiques de la valeur renvoyée. Vous pouvez utiliser le modèle Null pour empêcher la propagation de valeurs Null dans le reste de votre programme.

L’exemple suivant utilise le modèle Null et le modèle de variable.

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

Modèle Nameof

Le modèle nameof correspond à une chaîne quand sa valeur est égale à l’expression qui suit le mot clé nameof. Par exemple :

let f (str: string) =
    match str with
    | nameof str -> "It's 'str'!"
    | _ -> "It is not 'str'!"

f "str" // matches
f "asdf" // does not match

Consultez l’opérateur nameof pour obtenir plus d’informations sur les noms que vous pouvez prendre.

Voir aussi