Partilhar via


Parâmetros e argumentos (F#)

Este tópico descreve o suporte de linguagem para definição de parâmetros e passar argumentos para funções, métodos e propriedades. Ele inclui informações sobre como passar por referência e como definir e usar os métodos que podem levar a um número variável de argumentos.

Parâmetros e Argumentos

O termo parâmetro é usado para descrever os nomes de valores que são esperados ser fornecido. O termo argumento é usado para os valores fornecidos para cada parâmetro.

Parâmetros podem ser especificados na tupla ou curried do formulário ou em alguma combinação dos dois. Você pode passar argumentos usando um nome de parâmetro explícito. Parâmetros de métodos podem ser especificados como opcional e dadas um valor padrão.

Padrões de parâmetro

Parâmetros fornecidos para funções e métodos são, em geral, padrões, separados por espaços. Isso significa que, em princípio, qualquer um dos padrões descrito em Corresponder expressões (F#) pode ser usado em uma lista de parâmetros para uma função ou membro.

Métodos geralmente utilizam o formulário de tupla de passando argumentos. Esse processo atinge um resultado mais claro da perspectiva do outro.NET idiomas porque o formulário de tupla coincide com a maneira como os argumentos são passados no.NET métodos.

O formulário curried é usado com mais freqüência, com funções criadas usando let ligações.

O pseudocódigo a seguir mostra exemplos de tupla e argumentos de curried.

// Tuple form.
member this.SomeMethod(param1, param2) = ...
// Curried form.
let function1 param1 param2 = ...

Formulários combinados são possíveis quando alguns argumentos estão em tuplas e alguns não são.

let function2 param1 (param2a, param2b) param3 = ...

Para obter mais informações sobre o uso de funções curried, consulte parcial aplicação dos argumentos.

Outros padrões também podem ser usados em listas de parâmetro, mas se o padrão de parâmetro não corresponder a todas as entradas possíveis, pode haver uma correspondência incompleta em tempo de execução. A exceção MatchFailureException é gerado quando o valor de um argumento não coincide com os padrões especificados na lista de parâmetro. O compilador emitirá um aviso quando um padrão de parâmetro permite correspondências incompletas. Pelo menos um outro padrão é normalmente útil para listas de parâmetros e que é o padrão de curinga. Você pode usar o padrão de caractere curinga em uma lista de parâmetro quando você deseja simplesmente ignorar quaisquer argumentos fornecidos. O código a seguir ilustra o uso do padrão de caractere curinga em uma lista de argumentos.

let makeList _ = [ for i in 1 .. 100 -> i * i ]
// The arguments 100 and 200 are ignored.
let list1 = makeList 100
let list2 = makeList 200

O padrão de caractere curinga pode ser útil sempre que você não precisa de argumentos passados em, como em ponto de entrada principal para um programa, quando você não estiver interessado nos argumentos de linha de comando que normalmente são fornecidos como uma matriz de cadeia de caracteres, como no código a seguir.

[<EntryPoint>]
let main _ =
    printfn "Entry point!"
    0

Outros padrões que são usados algumas vezes argumentos são a as padrão e os padrões de identificador associados uniões discriminadas e padrões de ativo. Você pode usar o padrão de união discriminado de ocorrência única da seguinte maneira.

type Slice = Slice of int * int * string

let GetSubstring1 (Slice(p0, p1, text)) = 
    printfn "Data begins at %d and ends at %d in string %s" p0 p1 text
    text.[p0..p1]

let substring = GetSubstring1 (Slice(0, 4, "Et tu, Brute?"))
printfn "Substring: %s" substring

A saída é da seguinte maneira.

Data begins at 0 and ends at 4 in string Et tu, Brute?
Et tu

Você pode usar o as padrão para armazenar um valor correspondente como um valor de local, conforme é mostrado na seguinte linha de código.

let GetSubstring2 (Slice(p0, p1, text) as s) = s

Outro padrão que é usado ocasionalmente é uma função que deixa o último argumento sem nome fornecendo, como o corpo da função, uma expressão lambda que imediatamente realiza uma correspondência de padrão no argumento implícito. Um exemplo disso é a seguinte linha de código.

let isNil = function [] -> true | _::_ -> false

Este código define uma função que leva a uma lista genérica e retorna true se a lista estiver vazia, e false contrário. O uso dessas técnicas pode tornar o código mais difícil de ler.

Ocasionalmente, os padrões que envolvem incompletas correspondências são úteis, por exemplo, se você souber que as listas em seu programa tenham somente três elementos, você pode usar um padrão semelhante ao seguinte em uma lista de parâmetro.

let sum [a; b; c;] = a + b + c

O uso de padrões que têm uma correspondência incompleta melhor está reservado para o rápido desenvolvimento de protótipos e outros usos temporários. O compilador emitirá um aviso para esse tipo de código. Tais padrões não podem cobrir o caso geral de todas as entradas possíveis e, portanto, não são adequados para as APIs do componente.

Argumentos nomeados

Argumentos para os métodos que podem ser especificados por posição em uma lista de argumentos separados por ponto-e-vírgula, ou eles podem ser passados para um método explicitamente, fornecendo o nome, seguido por um sinal de igual e o valor a ser passado. Se especificado, fornecendo o nome, eles podem aparecer em uma ordem diferente daquela usada na declaração.

Argumentos nomeados podem tornar o código mais legível e mais adaptável para determinados tipos de alterações na API, como, por exemplo, uma reordenação de parâmetros do método.

Argumentos nomeados são permitidos somente para métodos, não para let-vinculado a funções, os valores de função ou lambda expressões.

O exemplo de código a seguir demonstra o uso de argumentos nomeados.

type SpeedingTicket() =
    member this.GetMPHOver(speed: int, limit: int) = speed - limit

let CalculateFine (ticket : SpeedingTicket) =
    let delta = ticket.GetMPHOver(limit = 55, speed = 70)
    if delta < 20 then 50.0 else 100.0

let ticket1 : SpeedingTicket = SpeedingTicket()
printfn "%f" (CalculateFine ticket1)

Parâmetros Opcionais

Você pode especificar um parâmetro opcional para um método usando um ponto de interrogação na frente do nome do parâmetro. Parâmetros opcionais são interpretados como F# tipo de opção, portanto, você pode consultá-los da maneira normal, que tipos de opção são consultados usando um match a expressão com Some e None. Parâmetros opcionais são permitidos somente em membros, não em funções criados usando let ligações.

Você também pode usar uma função defaultArg, que define um valor padrão de um argumento opcional. O defaultArg função usa o parâmetro opcional como primeiro argumento e o valor padrão como a segunda.

O exemplo a seguir ilustra o uso de parâmetros opcionais.

type DuplexType =
    | Full
    | Half

type Connection(?rate0 : int, ?duplex0 : DuplexType, ?parity0 : bool) =
    let duplex = defaultArg duplex0 Full
    let parity = defaultArg parity0 false
    let mutable rate = match rate0 with
                        | Some rate1 -> rate1
                        | None -> match duplex with
                                  | Full -> 9600
                                  | Half -> 4800
    do printfn "Baud Rate: %d Duplex: %A Parity: %b" rate duplex parity

let conn1 = Connection(duplex0 = Full)
let conn2 = Connection(duplex0 = Half)
let conn3 = Connection(300, Half, true)

A saída é da seguinte maneira.

Baud Rate: 9600 Duplex: Full Parity: false
Baud Rate: 4800 Duplex: Half Parity: false
Baud Rate: 300 Duplex: Half Parity: true

Passagem por referência

F# oferece suporte a byref palavra-chave, que especifica que um parâmetro é passado por referência. Isso significa que quaisquer alterações no valor são mantidas após a execução da função. Valores fornecidos para um byref parâmetro deve ser mutável. Como alternativa, você pode passar as células de referência do tipo apropriado.

Passando pela referência.NET idiomas evoluíram como uma maneira de retornar mais de um valor de uma função. Em F#, pode retornar uma coleção de itens para essa finalidade ou use uma célula mutável de referência como um parâmetro. O byref parâmetro principalmente é fornecido para interoperabilidade com.Bibliotecas NET.

Os exemplos a seguir ilustram o uso de byref palavra-chave. Observe que quando você usa uma célula de referência como um parâmetro, você deve criar uma célula de referência como um valor nomeado e utilize-o como o parâmetro, não basta adicionar o ref operador, como mostrado na primeira chamada para Increment o código a seguir. Porque a criação de uma célula de referência cria uma cópia do valor de base, a primeira chamada é incrementado apenas um valor temporário.

type Incrementor(z) =
    member this.Increment(i : int byref) =
       i <- i + z

let incrementor = new Incrementor(1)
let mutable x = 10
// Not recommended: Does not actually increment the variable.
incrementor.Increment(ref x)
// Prints 10.
printfn "%d" x  

let mutable y = 10
incrementor.Increment(&y)
// Prints 11.
printfn "%d" y 

let refInt = ref 10
incrementor.Increment(refInt)
// Prints 11.
printfn "%d" !refInt  

Você pode usar uma tupla como um valor de retorno para armazenar qualquer parâmetros deout no.Métodos de biblioteca NET. Como alternativa, você pode tratar a out parâmetro como um byref parâmetro. O exemplo de código a seguir ilustra ambas as direções.

// TryParse has a second parameter that is an out parameter
// of type System.DateTime.
let (b, dt) = System.DateTime.TryParse("12-20-04 12:21:00")

printfn "%b %A" b dt

// The same call, using an address of operator.
let mutable dt2 = System.DateTime.Now
let b2 = System.DateTime.TryParse("12-20-04 12:21:00", &dt2)

printfn "%b %A" b2 dt2

Matrizes de parâmetros

Ocasionalmente, é necessário definir uma função que leva a um número arbitrário de parâmetros do tipo heterogêneo. Não seria prático criar todos os métodos sobrecarregados possíveis para levar em conta todos os tipos que podem ser usados. A.NET da Microsoft oferece suporte a tais métodos por meio do recurso de matriz de parâmetro. Um método que leva a uma matriz de parâmetros na sua assinatura pode ser fornecido com um número arbitrário de parâmetros. Os parâmetros são colocados em uma matriz. O tipo de elementos de matriz determina os tipos de parâmetro que podem ser passados para a função. Se você definir a matriz de parâmetros com Object como o tipo de elemento, o código do cliente pode passar valores de qualquer tipo.

No F#, as matrizes de parâmetros só podem ser definidos nos métodos. Eles não podem ser usados em funções autônomas ou funções que são definidas em módulos.

Você pode definir uma matriz de parâmetros usando o atributo ParamArray. O ParamArray atributo só pode ser a última aplicada parâmetro.

O código a seguir ilustra ambas chamada um.Método NET que leva a uma matriz de parâmetros e a definição de um tipo de F# que tem um método que leva a uma matriz de parâmetros.

open System

type X() =
    member this.F([<ParamArray>] args: Object[]) =
        for arg in args do
            printfn "%A" arg

[<EntryPoint>]
let main _ =
    // call a .NET method that takes a parameter array, passing values of various types
    Console.WriteLine("a {0} {1} {2} {3} {4}", 1, 10.0, "Hello world", 1u, true)

    let xobj = new X()
    // call an F# method that takes a parameter array, passing values of various types
    xobj.F("a", 1, 10.0, "Hello world", 1u, true)
    0

Quando executado em um projeto, a saída do código anterior é o seguinte:

a 1 10 Hello world 1 True
"a"
1
10.0
"Hello world"
1u
true

Consulte também

Conceitos

Membros (F#)