Partilhar via


Padrões correspondentes (F#)

Padrões 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, decompõem a 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 durante o processamento de argumentos de funções no let ligações, expressões lambda e nos manipuladores de exceção associados com o try...with expressão. Para obter mais informações, consulte Corresponder expressões (F#), Deixe as ligações (F#), Expressões lambda: A diversão de palavra-chave (F#) e Exceções: O bloco try... com a expressão (F#).

Por exemplo, o match expressão, o pattern é o que segue o símbolo de pipe.

corresponder expression com

| patternquando 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 é examinada 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 uma correspondência não for encontrada, a próxima regra padrão é testada. Quando opcional condition parte é explicado na Corresponder expressões (F#).

Padrões suportados são mostrados na tabela a seguir. Em tempo de execução, a entrada é testada em relação a 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 de caso 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 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 que tem apenas os padrões de constantes de expressão pode ser comparada a uma instrução case em outros idiomas. A entrada é comparada com o valor literal e corresponde ao padrão 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 de variável e um padrão ou.

[<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 tupla, 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 nomeado caso. 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 é atribuído 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 manipulação de exceção, consulte Exceções: O bloco 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 ao proprietário. 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 onde esse padrão é usado em um let vinculação, o nome é adicionado como uma ligação para o escopo local.

O exemplo a seguir utiliza 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 ou.

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 corresponder a dois padrões. Os tipos de ambos os lados do padrão e devem ser compatíveis.

O exemplo a seguir é como detectZeroTuple mostrado na Padrão de tupla seção mais adiante neste tópico, mas aqui ambos 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 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 de e 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 de ser decomposto em seus elementos constituintes usando variáveis para cada posição de tupla de correspondência de padrão.

O exemplo a seguir demonstra o padrão de tupla e também usa os padrões de 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 apenas não participam de correspondência e não sã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 curinga 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 é usado freqüentemente 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. Freqüentemente, o padrão de curinga é 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. Elas 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 de 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 corresponder o contra um tipo de entrada. Se o tipo de entrada é um tipo derivado do tipo especificado no padrão ou uma correspondência, 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 a um valor nulo. Padrões de 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 impedir que valores nulos propagando para o resto 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

Corresponder expressões (F#)

Padrões de ativos (F#)

Outros recursos

Referência de linguagem do F#