Parâmetros e argumentos (F#)
Este tópico descreve o suporte ao idioma para a 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 para os 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 de formulárioou em alguma combinação dos dois. Você pode passar argumentos usando um nome de parâmetro de 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 Expressões match (F#) pode ser usado em uma lista de parâmetro para uma função ou um 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 a tupla formulário coincide com a maneira como os argumentos são passados no.NET métodos.
Costuma ser usada com funções criadas usando o formulário de curried let ligações.
O pseudocódigo a seguir mostra exemplos de tupla e curried de argumentos.
// 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 outros não.
let function2 param1 (param2a, param2b) param3 = ...
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 incompleta. Pelo menos um outro padrão é normalmente útil para listas de parâmetro 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 argumento .
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 os argumentos passado, como em um programa, o ponto de entrada do principal quando você não estiver interessado nos argumentos delinha 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 discriminadas uniões e padrões de ativos. Você pode usar o únicomaiúsculas e minúsculas discriminada união padrão 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
Padrões ativos podem ser útil como parâmetros, por exemplo, ao transformar um argumento em um formato desejado, como no exemplo a seguir:
type Point = { x : float; y : float }
let (| Polar |) { x = x; y = y} =
( sqrt (x*x + y*y), System.Math.Atan (y/ x) )
let radius (Polar(r, _)) = r
let angle (Polar(_, theta)) = theta
Você pode usar o as padrão para armazenar um valor correspondente como um valor 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ões no argumentoimplí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 apenas 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 abordam o maiúsculas e minúsculas geral de todas as entradas possíveis e, portanto, não são adequados para o componente APIs.
Argumentos nomeados
Argumentos para os métodos que podem ser especificados por posição em uma lista separada por vírgulas de argumento 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-funçõeslimite , função de valores ou expressões lambda.
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)
Em uma chamada para umconstrutorde classe, você pode definir os valores das propriedades da classe usando uma sintaxe semelhante dos argumentos nomeados. O exemplo a seguir mostra essa sintaxe.
type Account() =
let mutable balance = 0.0
let mutable number = 0
let mutable firstName = ""
let mutable lastName = ""
member this.AccountNumber
with get() = number
and set(value) = number <- value
member this.FirstName
with get() = firstName
and set(value) = firstName <- value
member this.LastName
with get() = lastName
and set(value) = lastName <- value
member this.Balance
with get() = balance
and set(value) = balance <- value
member this.Deposit(amount: float) = this.Balance <- this.Balance + amount
member this.Withdraw(amount: float) = this.Balance <- this.Balance - amount
let account1 = new Account(AccountNumber=8782108,
FirstName="Darren", LastName="Parker",
Balance=1543.33)
Para obter mais informações, consulte construtores (F#).
Parâmetros Opcionais
Você pode especificar um parâmetro opcional para um método por meio de um ponto de interrogação na frente do nome do parâmetro . Parâmetros opcionais são interpretados como o tipo de opção F#, para que você possa consulta -los da forma regular 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 por meio do let ligações.
Você também pode usar uma função defaultArg, que define um valor padrão de um argumentode 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 a fazer referência a células do tipo apropriado.
Passando pela referência.NET diferentes evoluíram como uma forma para retornar mais de um valor de uma função. Na F#, você pode retornar uma coleção de itens para essa finalidade ou utilizar uma célula de referência mutáveis como parâmetro. O byref parâmetro é fornecido principalmente para interoperabilidade com.NET comuns.
Os exemplos a seguir ilustram o uso da 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 o uso que, como o parâmetro, não basta adicionar o ref operador conforme mostrado na primeira chamada para Increment no código a seguir. Como a criação de uma célula de referência cria uma cópia do valor de base, a primeira chamada incrementa 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 retornado para armazenar qualquer out parâmetros no.Métodos de biblioteca de rede. 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 um número arbitrário de parâmetros do tipo heterogêneo. Não seria prático criar sobrecarregados de todos os possíveis métodos para levar em conta todos os tipos que podem ser usados. A.NET plataforma oferece suporte para tais métodos por meio do parâmetro matriz recurso. Um método que usa uma matriz de parâmetro na sua assinatura pode ser fornecida com um número arbitrário de parâmetros. Os parâmetros são colocados em uma matriz. O tipo dos elementos de matriz determina os tipos de parâmetro que podem ser passados para a função. Se você definir a matriz de parâmetro com Object como o tipo de elemento, em seguida, o código de cliente pode passar valores de qualquer tipo.
No F#, matrizes de parâmetro 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âmetro usando o atributodo ParamArray. O ParamArray atributo só pode ser aplicada para o último parâmetro.
O código a seguir ilustra as duas chamada um.NET método que usa uma matriz de parâmetro e a definição de um tipo de F# que tem um método que leva a uma matriz de parâmetro .
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