Padrões correspondentes (F#)
Padrões de são regras para transformar os dados de entrada.Eles são usados em todo o idioma F# para comparar dados com uma estrutura lógica ou estruturas, decompor dados em partes constituintes ou extrair informações de dados de várias maneiras.
Comentários
Padrões são usadas em muitas construções de linguagem, como o match expressão.Eles são usados quando você está processando os argumentos para funções na let ligações, expressões lambda e no manipulador de exceção associado com o try...with expressão.Para obter mais informações, consulte Expressões de correspondência (F#), permitir que as ligações (F#), As expressões lambda: Diversão palavra-chave (F#) e Exceções: Try... com a expressão (F#).
Por exemplo, na match a expressão, o pattern é o que se segue o símbolo pipe.
corresponde ao expression com
| pattern when condition -> result-expression
...
Cada padrão age como uma regra para transformar a entrada de alguma maneira.No match a expressão, cada padrão é examinado por sua vez, para ver se os dados de entrada serão compatíveis com o padrão.Se uma correspondência for encontrada, a expressão do resultado é executada.Se não houver uma correspondência, a próxima regra padrão é testada.Quando opcional condition parte é explicado na Expressões de correspondência (F#).
Padrões suportados são mostrados na tabela a seguir.Em tempo de execução, a entrada é verificada com cada um dos seguintes padrões na ordem listada na tabela e padrões são aplicada recursivamente, do primeiro ao último como aparecem no seu código e da esquerda para a direita para os padrões em cada linha.
Nome |
Descrição |
Exemplo |
---|---|---|
Padrão de constante |
Qualquer numérico, caractere, ou seqüência de caracteres literal, uma constante de enumeração ou um identificador definido de literal |
1.0, "test", 30, Color.Red |
Padrão de identificador |
Um valor case de uma união discriminada, um rótulo de exceção ou uma ocorrência do padrão ativo |
Some(x) Failure(msg) |
Padrão de variável |
identifier |
a |
aspadrão |
padrão de como identificador |
(a, b) as tuple1 |
OU padrão |
pattern1 | pattern2 |
([h] | [h; _]) |
Padrão AND |
pattern1 & pattern2 |
(a, b) & (_, "test") |
Padrão de contras |
identifier :: list-identifier |
h :: t |
Padrão de lista |
[ pattern_1; ...; pattern_n ] |
[ a; b; c ] |
Padrão de matriz |
[| pattern_1; ..; pattern_n ] |
[| a; b; c |] |
Entre parênteses padrão |
( pattern ) |
( a ) |
Padrão de tupla |
( pattern_1, ..., pattern_n ) |
( a, b ) |
Padrão de registro |
{ identifier1 = pattern_1; ...; identifier_n = pattern_n } |
{ Name = name; } |
Padrão de curinga |
_ |
_ |
Padrão em conjunto com a anotação de tipo |
pattern : type |
a : int |
Tipo padrão de teste |
:?type asidentifier |
:? System.DateTime as dt |
Padrão de nulo |
Nulo |
null |
Padrões de constantes
Os padrões de constantes são numéricos, caracteres e literais de seqüência de caracteres, constantes de enumeração (com o nome de tipo de enumeração incluído).A match expressão que contém somente os padrões de constantes pode ser comparada a uma instrução case em outros idiomas.A entrada é comparada com o valor literal e o padrão corresponde a se os valores são iguais.O tipo do literal deve ser compatível com o tipo da entrada.
O exemplo a seguir demonstra o uso de padrões literais e também usa um padrão variável e um padrão de 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
Outro exemplo de um padrão de literal é um padrão com base em constantes de enumeração.Quando você usa constantes de enumeração, você deve especificar o nome do tipo de enumeração.
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
Padrões de identificador
Se o padrão é uma seqüência de caracteres que formam um identificador válido, o formulário do identificador determina como o padrão é correspondido.Se o identificador é maior do que um único caractere e começa com um caractere maiúsculo, o compilador tenta fazer uma correspondência para o padrão de identificador.O identificador para esse padrão pode ser um valor marcado com o atributo Literal, uma ocorrência de união discriminada, um identificador de exceção ou uma ocorrência do padrão ativo.Se nenhum identificador correspondente for encontrado, a correspondência falha e a próxima regra padrão, o padrão de variável é comparada à entrada.
Os padrões de união discriminados podem ser simples chamado casos ou podem ter um valor ou uma tupla que contém vários valores.Se houver um valor, você deve especificar um identificador para o valor ou no caso de uma coleção de itens, você deve fornecer um padrão de tupla com um identificador para cada elemento da tupla.Consulte os exemplos nesta seção para obter exemplos de código.
O option o tipo é uma união discriminada que tem dois casos, Some e None.Um caso (Some) tem um valor, mas o outro (None) é apenas um caso nomeado.Portanto, Some precisa ter uma variável para o valor associado a Some caso, mas None deve aparecer sozinha.No código a seguir, a variável var1 recebe o valor que é obtido pela correspondência para o Some case.
let printOption (data : int option) =
match data with
| Some var1 -> printfn "%d" var1
| None -> ()
No exemplo a seguir, o PersonName união discriminada contém uma mistura de cadeias de caracteres e caracteres que representam formas possíveis de nomes.Os casos de união discriminada são 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
Active padrões permitem que você definir a correspondência de padrão personalizado mais complexos.Para obter mais informações sobre padrões de ativos, consulte Padrões de ativos (F#).
O caso em que o identificador é uma exceção é usado na correspondência de padrões no contexto de manipuladores de exceção.Para obter informações sobre a correspondência de padrão de tratamento de exceções, consulte Exceções: Try... com a expressão (F#).
Padrões de variáveis
O padrão de variável atribui o valor que está sendo correspondido a um nome de variável, em seguida, está disponível para uso na expressão à direita da execução de -> símbolo.Qualquer entrada corresponde a um padrão variável sozinho, mas os padrões de variáveis aparecem dentro de outros padrões, permitindo, portanto, a estruturas mais complexas, como arrays para ser decomposto em variáveis e de tuplas.
O exemplo a seguir demonstra um padrão variável dentro de um padrão 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 padrão
O as padrão é um padrão que tem um as cláusula acrescentada a ele.O as cláusula vincula o valor correspondente a um nome que pode ser usado na expressão de execução de um match expressão, ou, no caso em que esse padrão é usado em um let de vinculação, o nome é adicionado como uma ligação para o escopo local.
O exemplo a seguir usa um as padrão.
let (var1, var2) as tuple1 = (1, 2)
printfn "%d %d %A" var1 var2 tuple1
OU padrão
O padrão ou é usado quando os dados de entrada podem corresponder a vários padrões, e você deseja executar o mesmo código como resultado.Os tipos de ambos os lados do padrão ou devem ser compatíveis.
O exemplo a seguir demonstra o padrão de 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)
E o padrão
O padrão e requer que a entrada coincide com dois padrões.Os tipos de ambos os lados do padrão e devem ser compatíveis.
O exemplo a seguir é como detectZeroTuple mostra a Tupla padrão seção mais adiante neste tópico, mas aqui os dois var1 e var2 são obtidas como valores usando o padrão E.
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)
Contras padrão
O padrão de contras é usado para decompor uma lista para o primeiro elemento, o heade uma lista que contém os elementos restantes, o cauda.
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
Padrão de lista
O padrão de lista permite listas para ser decomposto em um número de elementos.O próprio padrão de lista pode corresponder apenas listas de um 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 [ ] )
Padrão de matriz
O padrão de matriz se parece com o padrão de lista e pode ser usado para decompor as matrizes de um período específico.
// 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 [| |] )
Entre parênteses padrão
Parênteses podem ser agrupados em torno de padrões para atingir a associatividade desejada.No exemplo a seguir, os parênteses são usados para controlar a associação entre um padrão AND e um padrão de contras.
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
Padrão de tupla
O padrão de tupla corresponde a entrada no formulário de tupla e permite que a tupla ser decomposto em seus elementos constituintes por meio de padrões coincidentes variáveis para cada posição de tupla.
O exemplo a seguir demonstra o padrão de tupla e também usa padrões literais, padrões de variáveis e o padrão de curinga.
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)
Padrão de registro
O padrão de registro é usado para decompor registros para extrair os valores dos campos.O padrão não tem que fazer referência a todos os campos do registro; os campos omitidos basta não participam de correspondência e não serão extraídos.
// 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"
Padrão de curinga
O padrão de caractere curinga é representado pelo sublinhado (_) de caracteres e corresponde a qualquer entrada, assim como o padrão de variável, exceto que a entrada é descartada em vez de atribuído a uma variável.O padrão de caractere curinga é freqüentemente usado dentro de outros padrões como um espaço reservado para os valores que não são necessários na expressão à direita da -> símbolo.O padrão de curinga freqüentemente é usado no final de uma lista de padrões para coincidir com qualquer entrada incomparável.O padrão de caractere curinga é demonstrado em muitos exemplos de código neste tópico.Consulte o código anterior para obter um exemplo.
Padrões que têm anotações de tipo
Os padrões podem ter anotações de tipo.Eles se comportam como outras anotações de tipo e orientam a inferência de tipos como outras anotações de tipo.Parênteses são exigidos ao redor de anotações de tipo em padrões.O código a seguir mostra um padrão que tem uma anotação de tipo.
let detect1 x =
match x with
| 1 -> printfn "Found a 1!"
| (var1 : int) -> printfn "%d" var1
detect1 0
detect1 1
Tipo padrão de teste
O padrão de teste de tipo é usado para coincidir com a entrada em relação a um tipo.Se o tipo de entrada é uma correspondência com (ou um tipo derivado de) o tipo especificado no padrão, a correspondência é bem-sucedida.
O exemplo a seguir demonstra o padrão de teste 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."
| _ -> ()
Padrão de nulo
O padrão de nulo coincide com o valor nulo que pode aparecer quando você estiver trabalhando com tipos que permitem um valor nulo.Padrões nulos são usadas com freqüência quando interoperar com .NET Framework código.Por exemplo, o valor de retorno de um.NET API pode ser a entrada para um match expressão.Você pode controlar o fluxo do programa com base em se o valor de retorno é nulo e também outras características do valor retornado.Você pode usar o padrão null para evitar valores nulos seja propagada para o restante do seu programa.
O exemplo a seguir usa o padrão de nulo e o padrão de variável.
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()
Consulte também
Referência
Expressões de correspondência (F#)