Critères spéciaux
Les modèles sont des règles pour transformer les données d’entrée. Ils sont utilisés dans F# pour comparer des données avec une structure logique ou des structures, décomposer des données en parties constituantes ou extraire des informations de données de différentes manières.
Remarques
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 des liaisons let
, des expressions lambda et dans les gestionnaires d’exceptions associés à l’expression try...with
. Pour plus d'informations, consultez Match Expressions, let Bindings, Lambda Expressionsfun
: Le mot-clé, ettry...with
Exceptions : L'expression .
Par exemple, dans l’expression match
, le modèle est ce qui suit le symbole de pipe.
match expression with
| pattern [ when condition ] -> result-expression
...
Chaque modèle agit comme une règle pour transformer l’entrée d’une certaine manière. 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 est introuvable, la règle de modèle suivante est testée. La partie optionnelle de la condition when est expliquée dans Match Expressions.
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 la table, et les modèles sont appliqués de manière récursive, de premier à dernier à mesure qu’elles apparaissent dans votre code, et de gauche à droite pour les modèles sur chaque ligne.
Nom | Description | Exemple |
---|---|---|
Modèle constant | Tout littéral numérique, caractère ou chaîne, constante d’énumération ou 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 | identifiant | a |
modèle as |
motif en tant qu'identifiant | (a, b) as tuple1 |
Modèle OR | pattern1 | pattern2 | ([h] | [h; _]) |
Modèle AND | pattern1 & pattern2 | (a, b) & (_, "test") |
Cons motif | identifiant :: list-identifier | h :: t |
Modèle de liste | [ pattern_1; ... ; pattern_n ] | [ a; b; c ] |
Motif 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 |
Motif nul | zéro | null |
Nom du motif | nom de l'expr | nameof str |
Modèles constants
Les modèles constants sont des littéraux numériques, des caractères et des littéraux de chaîne, des constantes d’énumération (avec le nom du type d’énumération inclus). Une expression match
qui a uniquement des modèles constants 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 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 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 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 Littéral, un cas d’union discriminatoire, 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é à l’entrée.
Les modèles d’union discriminante peuvent être des cas simples et nommés, avoir une valeur, ou encore être un tuple contenant plusieurs valeurs. S’il existe une valeur, vous devez spécifier un identificateur pour la valeur. Dans le cas d’un tuple, vous devez fournir un modèle 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. Consultez les exemples de code de cette section pour obtenir des exemples.
Le type option
est une union discriminatoire qui a deux cas, Some
et None
. Un cas (Some
) a une valeur, mais l’autre (None
) est juste un cas nommé. Par conséquent, Some
doit avoir une variable pour la valeur associée au cas Some
, mais None
doit apparaître par lui-même. Dans le code suivant, la variable var1
reçoit la valeur obtenue en correspondant au 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 représentant 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 discriminatoires 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 discriminatoire 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 modèle 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é est facultative. Dans l’exemple précédent, les deux Circle(r)
et Circle(radius = r)
ont le même effet.
Lorsque vous spécifiez plusieurs champs, utilisez le point-virgule (;) comme séparateur.
match shape with
| Rectangle(height = h; width = w) -> printfn $"Rectangle with height %f{h} and width %f{w}"
| _ -> ()
Les motifs actifs vous permettent de définir une correspondance de motifs personnalisés plus complexe. Pour plus d’informations sur les modèles actifs, consultez modèles actifs.
Le cas dans lequel l'identificateur est une exception est utilisé dans l'appariement de motifs dans le contexte des gestionnaires d'exceptions. Pour plus d’informations sur la correspondance des modèles 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 variable correspond uniquement à n’importe quelle entrée, mais les modèles variables apparaissent souvent dans d’autres modèles, ce qui permet aux structures plus complexes telles que les tuples et les tableaux d’être décomposés en variables.
L’exemple suivant illustre un modèle variable dans un modèle 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)
Modèle as
Le modèle as
est un modèle qui a une clause as
ajoutée à celle-ci. La clause as
lie la valeur correspondante à un nom qui peut être utilisé dans l’expression d’exécution d’une expression match
ou, dans le cas où ce modèle est utilisé dans une liaison let
, le nom est ajouté comme liaison à l’étendue locale.
L’exemple suivant utilise un modèle as
.
let (var1, var2) as tuple1 = (1, 2)
printfn "%d %d %A" var1 var2 tuple1
Motif 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 en conséquence. 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 d'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 Tuple plus loin dans cette rubrique, mais ici, var1
et var2
sont obtenus comme 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)
Motif cons
Le motif cons est utilisé pour décomposer une liste en un premier élément, la tête, et une liste contenant les éléments restants, la queue.
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 aux listes d’être décomposées en un certain nombre d’éléments. Le modèle de liste lui-même ne peut correspondre qu’à 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 les 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
Motif tuple
Le Modèle de correspondance correspond à une entrée sous forme de tuple et permet de décomposer le tuple en ses éléments constitutifs en utilisant des variables de correspondance pour chaque position dans le tuple.
L'exemple suivant illustre le motif tuple et utilise également des motifs littéraux, des motifs variables et le motif 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 pour 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"
Caractère générique
Le modèle générique est représenté par le caractère 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 motif générique est souvent utilisé dans d’autres motifs comme espace réservé pour les valeurs qui ne sont pas nécessaires dans l’expression située à droite du symbole ->
. Le motif générique est également fréquemment utilisé à la fin d'une liste de motifs pour correspondre à toute entrée non correspondante. Le caractère générique est utilisé 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 avec (ou un type dérivé) du type spécifié 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 si un identificateur est d’un type dérivé particulier, vous n’avez pas besoin de la as identifier
partie 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 nul
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 de retour d’une API .NET peut être l’entrée d’une expression match
. Vous pouvez contrôler le flux du programme en fonction de si la valeur de retour est nulle ou non, ainsi que d'autres caractéristiques de la valeur retournée. Vous pouvez utiliser le modèle Null pour empêcher la propagation de valeurs Null vers 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()
Le motif Null est également recommandé pour les capacités de nullabilité de F# 9 :
let len (str: string | null) =
match str with
| null -> -1
| s -> s.Length
De même, vous pouvez utiliser de nouveaux motifs dédiés à la nullabilité :
let let str = // str is inferred to be `string | null`
match str with
| Null -> -1
| NonNull (s: string) -> s.Length
Nom du motif
Le modèle nameof
correspond à une chaîne lorsque 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
Voir l'opérateur nameof
pour plus d'informations sur ce que vous pouvez prendre comme nom.