Coincidencia de modelos
Los patrones son reglas para transformar los datos de entrada. Se usan en F# para comparar datos con estructuras o estructuras lógicas, descomponer datos en partes constituyentes o extraer información de los datos de varias maneras.
Observaciones
Los patrones se usan en muchas construcciones de lenguaje, como la match expresión . Se usan cuando se están procesando argumentos para funciones en enlaces, expresiones lambda y en los controladores de excepciones let asociados a la try...with expresión. Para obtener más información, vea Expresionesde coincidencia , let Bindings, Lambda Expressions: The fun Keywordy Exceptions: The try...with Expression.
Por ejemplo, en la expresión , el patrón es lo que match sigue al símbolo de canalización.
match expression with
| pattern [ when condition ] -> result-expression
...
Cada patrón actúa como una regla para transformar la entrada de alguna manera. En la match expresión, cada patrón se examina a su vez para ver si los datos de entrada son compatibles con el patrón. Si se encuentra una coincidencia, se ejecuta la expresión de resultado. Si no se encuentra una coincidencia, se prueba la siguiente regla de patrón. El elemento opcional cuando la condición se explica en Expresiones de coincidencia.
Los patrones admitidos se muestran en la tabla siguiente. En tiempo de ejecución, la entrada se prueba con cada uno de los siguientes patrones en el orden indicado en la tabla, y los patrones se aplican de forma recursiva, de primero a último cuando aparecen en el código y de izquierda a derecha para los patrones de cada línea.
| Nombre | Descripción | Ejemplo |
|---|---|---|
| Patrón de constante | Cualquier literal numérico, de carácter o de cadena, una constante de enumeración o un identificador literal definido | 1.0, "test", 30, Color.Red |
| Patrón de identificador | Valor de caso de una unión discriminada, una etiqueta de excepción o un caso de patrón activo | Some(x)Failure(msg) |
| Patrón de variable | identifier | a |
Patrón as |
patrón como identificador | (a, b) as tuple1 |
| Patrón OR | pattern1 | pattern2 | ([h] | [h; _]) |
| Patrón AND | pattern1 & pattern2 | (a, b) & (_, "test") |
| Patrón Cons | identifier :: list-identifier | h :: t |
| Patrón de lista | [ pattern_1; ... ; pattern_n ] | [ a; b; c ] |
| Patrón de matriz | [| pattern_1; ..; pattern_n |] | [| a; b; c |] |
| Patrón entre paréntesis | ( patrón ) | ( a ) |
| Patrón de tupla | ( pattern_1, ... , pattern_n ) | ( a, b ) |
| Patrón de registro | { identifier1 = pattern_1; ... ; identifier_n = pattern_n } | { Name = name; } |
| Patrón de caracteres comodín | _ | _ |
| Patrón junto con anotación de tipo | pattern : type | a : int |
| Patrón de prueba de tipo | :? type [ as identifier ] | :? System.DateTime as dt |
| Patrón null | null | null |
| Patrón Nameof | nameof expr | nameof str |
Patrones constantes
Los patrones constantes son literales numéricos, de caracteres y de cadena, constantes de enumeración (con el nombre de tipo de enumeración incluido). Una match expresión que solo tiene patrones constantes se puede comparar con una instrucción case en otros lenguajes. La entrada se compara con el valor literal y el patrón coincide si los valores son iguales. El tipo del literal debe ser compatible con el tipo de la entrada.
En el ejemplo siguiente se muestra el uso de patrones literales y también se usa un patrón de variable y un patrón 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
Otro ejemplo de un patrón literal es un patrón basado en constantes de enumeración. Debe especificar el nombre del tipo de enumeración cuando use constantes de enumeración.
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
Patrones de identificador
Si el patrón es una cadena de caracteres que forma un identificador válido, la forma del identificador determina cómo se compara el patrón. Si el identificador es mayor que un solo carácter y comienza con un carácter en mayúsculas, el compilador intenta hacer una coincidencia con el patrón de identificador. El identificador de este patrón podría ser un valor marcado con el atributo Literal, un caso de unión discriminada, un identificador de excepción o un caso de patrón activo. Si no se encuentra ningún identificador de coincidencia, se produce un error en la coincidencia y la siguiente regla de patrón, el patrón de variable, se compara con la entrada.
Los patrones de unión discriminada pueden ser casos con nombre simples o pueden tener un valor o una tupla que contenga varios valores. Si hay un valor, debe especificar un identificador para el valor. En el caso de una tupla, debe proporcionar un patrón de tupla con un identificador para cada elemento de la tupla o un identificador con un nombre de campo para uno o varios campos de unión con nombre. Vea los ejemplos de código de esta sección para obtener ejemplos.
El option tipo es una unión discriminada que tiene dos casos, y Some None . Un caso ( Some ) tiene un valor, pero el otro ( None ) es simplemente un caso con nombre. Por lo Some tanto, debe tener una variable para el valor asociado al Some caso, pero None debe aparecer por sí mismo. En el código siguiente, a la variable se le asigna el valor que se obtiene al coincidir var1 con el Some caso.
let printOption (data : int option) =
match data with
| Some var1 -> printfn "%d" var1
| None -> ()
En el ejemplo siguiente, la PersonName unión discriminada contiene una combinación de cadenas y caracteres que representan posibles formas de nombres. Los casos de la unión discriminada FirstOnly son LastOnly , y 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
Para las uniones discriminadas que tienen campos con nombre, use el signo igual (=) para extraer el valor de un campo con nombre. Por ejemplo, considere una unión discriminada con una declaración como la siguiente.
type Shape =
| Rectangle of height : float * width : float
| Circle of radius : float
Puede usar los campos con nombre en una expresión de coincidencia de patrones como se muestra a continuación.
let matchShape shape =
match shape with
| Rectangle(height = h) -> printfn $"Rectangle with length %f{h}"
| Circle(r) -> printfn $"Circle with radius %f{r}"
El uso del campo con nombre es opcional, por lo que en el ejemplo anterior, Circle(r) y tienen el mismo Circle(radius = r) efecto.
Al especificar varios campos, use el punto y coma (;) como separador.
match shape with
| Rectangle(height = h; width = w) -> printfn $"Rectangle with height %f{h} and width %f{w}"
| _ -> ()
Los patrones activos permiten definir coincidencias de patrones personalizados más complejas. Para obtener más información sobre los patrones activos, vea Patrones activos.
El caso en el que el identificador es una excepción se usa en la coincidencia de patrones en el contexto de los controladores de excepciones. Para obtener información sobre la coincidencia de patrones en el control de excepciones, vea Excepciones: try...with expresión.
Patrones de variables
El patrón de variable asigna el valor que coincide con un nombre de variable, que luego está disponible para su uso en la expresión de ejecución a la derecha del -> símbolo. Un patrón de variable solo coincide con cualquier entrada, pero los patrones de variables suelen aparecer dentro de otros patrones, lo que permite que estructuras más complejas, como tuplas y matrices, se descomponen en variables.
En el ejemplo siguiente se muestra un patrón de variable dentro de un patrón de 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)
como patrón
El as patrón es un patrón que tiene una cláusula as anexada. La cláusula enlaza el valor coincidente a un nombre que se puede usar en la expresión de ejecución de una expresión o, en el caso de que este patrón se utilice en un enlace, el nombre se agrega como enlace al as match ámbito let local.
En el ejemplo siguiente se usa un as patrón .
let (var1, var2) as tuple1 = (1, 2)
printfn "%d %d %A" var1 var2 tuple1
Patrón OR
El patrón OR se usa cuando los datos de entrada pueden coincidir con varios patrones y desea ejecutar el mismo código como resultado. Los tipos de ambos lados del patrón OR deben ser compatibles.
En el ejemplo siguiente se muestra el patrón 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)
Patrón AND
El patrón AND requiere que la entrada coincida con dos patrones. Los tipos de ambos lados del patrón AND deben ser compatibles.
El ejemplo siguiente es como se muestra en la sección Patrón de tupla más adelante en este tema, pero aquí y se obtienen como valores mediante detectZeroTuple var1 el patrón var2 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)
Patrón cons
El patrón cons se usa para descomponer una lista en el primer elemento, el encabezado y una lista que contiene los elementos restantes, la cola.
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
Patrón de lista
El patrón de lista permite que las listas se descomponen en varios elementos. El propio patrón de lista solo puede coincidir con listas de un número específico de elementos.
// 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 [ ] )
Patrón de matriz
El patrón de matriz se parece al patrón de lista y se puede usar para descomponer matrices de una longitud específica.
// 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 [| |] )
Patrón entre paréntesis
Los paréntesis se pueden agrupar en torno a patrones para lograr la asociatividad deseada. En el ejemplo siguiente, se usan paréntesis para controlar la asociatividad entre un patrón AND y un patrón 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
Patrón de tupla
El patrón de tupla coincide con la entrada en forma de tupla y permite que la tupla se descompona en sus elementos constituyentes mediante variables de coincidencia de patrones para cada posición de la tupla.
En el ejemplo siguiente se muestra el patrón de tupla y también se usan patrones literales, patrones de variables y el patrón de caracteres comodín.
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)
Patrón de registro
El patrón de registro se usa para descomponer registros para extraer los valores de los campos. El patrón no tiene que hacer referencia a todos los campos del registro; los campos omitidos simplemente no participan en la búsqueda de coincidencias y no se extraen.
// 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"
Patrón de caracteres comodín
El patrón de caracteres comodín se representa mediante el carácter de subrayado ( ) y coincide con cualquier entrada, al igual que el patrón de variable, salvo que la entrada se descarta en lugar de _ asignarse a una variable. El patrón comodín se suele usar dentro de otros patrones como marcador de posición para los valores que no son necesarios en la expresión a la derecha del -> símbolo. El patrón de caracteres comodín también se usa con frecuencia al final de una lista de patrones para que coincida con cualquier entrada no coincidente. El patrón de caracteres comodín se muestra en muchos ejemplos de código de este tema. Vea el código anterior para ver un ejemplo.
Patrones que tienen anotaciones de tipo
Los patrones pueden tener anotaciones de tipo. Se comportan como otras anotaciones de tipo e inferencia de guía como otras anotaciones de tipo. Los paréntesis son necesarios en torno a las anotaciones de tipo en patrones. El código siguiente muestra un patrón que tiene una anotación de tipo.
let detect1 x =
match x with
| 1 -> printfn "Found a 1!"
| (var1 : int) -> printfn "%d" var1
detect1 0
detect1 1
Patrón de prueba de tipo
El patrón de prueba de tipo se usa para hacer coincidir la entrada con un tipo. Si el tipo de entrada coincide con (o un tipo derivado de ) con el tipo especificado en el patrón, la coincidencia se realiza correctamente.
En el ejemplo siguiente se muestra el patrón de prueba de tipo.
open System.Windows.Forms
let RegisterControl(control:Control) =
match control with
| :? Button as button -> button.Text <- "Registered."
| :? CheckBox as checkbox -> checkbox.Text <- "Registered."
| _ -> ()
Si solo está comprobando si un identificador es de un tipo derivado determinado, no necesita la parte del patrón, como se muestra en as identifier el ejemplo siguiente:
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"
| _ -> ()
Patrón NULL
El patrón null coincide con el valor NULL que puede aparecer cuando se trabaja con tipos que permiten un valor NULL. Los patrones NULL se usan con frecuencia al interoperar con .NET Framework código. Por ejemplo, el valor devuelto de una API de .NET podría ser la entrada a una match expresión. Puede controlar el flujo de programa en función de si el valor devuelto es NULL y también de otras características del valor devuelto. Puede usar el patrón null para evitar que los valores NULL se propaguen al resto del programa.
En el ejemplo siguiente se usa el patrón NULL y el patrón 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()
Patrón Nameof
El nameof patrón coincide con una cadena cuando su valor es igual a la expresión que sigue a la palabra nameof clave . Por ejemplo:
let f (str: string) =
match str with
| nameof str -> "It's 'str'!"
| _ -> "It is not 'str'!"
f "str" // matches
f "asdf" // does not match
Consulte el nameof operador para obtener información sobre lo que puede tomar un nombre.