Parametri e argomenti
In questo argomento viene descritto il supporto del linguaggio per la definizione di parametri e il passaggio di argomenti a funzioni, metodi e proprietà. Include informazioni su come passare per riferimento e su come definire e usare metodi che possono accettare un numero variabile di argomenti.
Parametri e argomenti
Il termine parametro viene usato per descrivere i nomi per i valori che devono essere forniti. Il termine argomento viene usato per i valori forniti per ogni parametro.
I parametri possono essere specificati in forma tupla o curried oppure in una combinazione dei due. È possibile passare argomenti usando un nome di parametro esplicito. I parametri dei metodi possono essere specificati come facoltativi e in base a un valore predefinito.
Modelli di parametri
I parametri forniti a funzioni e metodi sono, in generale, modelli separati da spazi. Ciò significa che, in linea di principio, qualsiasi modello descritto in Espressioni di corrispondenza può essere usato in un elenco di parametri per una funzione o un membro.
I metodi usano in genere la forma di tupla di passaggio di argomenti. In questo modo si ottiene un risultato più chiaro dal punto di vista di altri linguaggi .NET perché il formato della tupla corrisponde al modo in cui gli argomenti vengono passati nei metodi .NET.
Il form curried viene spesso usato con le funzioni create usando let
le associazioni.
Lo pseudocodice seguente mostra esempi di tupla e argomenti curried.
// Tuple form.
member this.SomeMethod(param1, param2) = ...
// Curried form.
let function1 param1 param2 = ...
I moduli combinati sono possibili quando alcuni argomenti sono in tuple e alcuni non lo sono.
let function2 param1 (param2a, param2b) param3 = ...
Altri modelli possono essere usati anche negli elenchi di parametri, ma se il modello di parametro non corrisponde a tutti gli input possibili, potrebbe verificarsi una corrispondenza incompleta in fase di esecuzione. L'eccezione MatchFailureException
viene generata quando il valore di un argomento non corrisponde ai modelli specificati nell'elenco di parametri. Il compilatore genera un avviso quando un criterio di parametro consente corrispondenze incomplete. Almeno un altro modello è comunemente utile per gli elenchi di parametri e questo è il modello con caratteri jolly. Usare il criterio con caratteri jolly in un elenco di parametri quando si desidera semplicemente ignorare tutti gli argomenti forniti. Il codice seguente illustra l'uso del criterio con caratteri jolly in un elenco di argomenti.
let makeList _ = [ for i in 1 .. 100 -> i * i ]
// The arguments 100 and 200 are ignored.
let list1 = makeList 100
let list2 = makeList 200
Il criterio con caratteri jolly può essere utile ogni volta che non sono necessari gli argomenti passati, ad esempio nel punto di ingresso principale a un programma, quando non si è interessati agli argomenti della riga di comando normalmente forniti come matrice di stringhe, come nel codice seguente.
[<EntryPoint>]
let main _ =
printfn "Entry point!"
0
Altri modelli usati talvolta negli argomenti sono il as
modello e i modelli di identificatore associati a unioni discriminate e modelli attivi. È possibile usare il modello di unione discriminante con maiuscole e minuscole come indicato di seguito.
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
L'output è indicato di seguito.
Data begins at 0 and ends at 4 in string Et tu, Brute?
Et tu
I modelli attivi possono essere utili come parametri, ad esempio quando si trasforma un argomento in un formato desiderato, come nell'esempio seguente:
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
È possibile usare il as
modello per archiviare un valore corrispondente come valore locale, come illustrato nella riga di codice seguente.
let GetSubstring2 (Slice(p0, p1, text) as s) = s
Un altro criterio usato occasionalmente è una funzione che lascia l'ultimo argomento senza nome fornendo, come corpo della funzione, un'espressione lambda che esegue immediatamente una corrispondenza del criterio sull'argomento implicito. Un esempio è la riga di codice seguente.
let isNil = function [] -> true | _::_ -> false
Questo codice definisce una funzione che accetta un elenco generico e restituisce true
se l'elenco è vuoto e false
in caso contrario. L'uso di tali tecniche può rendere il codice più difficile da leggere.
In alcuni casi, i modelli che coinvolgono corrispondenze incomplete sono utili, ad esempio, se si sa che gli elenchi nel programma hanno solo tre elementi, è possibile usare un modello simile al seguente in un elenco di parametri.
let sum [a; b; c;] = a + b + c
L'uso di modelli con corrispondenze incomplete è meglio riservato per la creazione rapida di prototipi e altri usi temporanei. Il compilatore genererà un avviso per tale codice. Tali modelli non possono coprire il caso generale di tutti gli input possibili e pertanto non sono adatti per le API dei componenti.
Argomenti denominati
Gli argomenti per i metodi possono essere specificati dalla posizione in un elenco di argomenti delimitati da virgole oppure possono essere passati a un metodo in modo esplicito specificando il nome, seguito da un segno di uguale e dal valore da passare. Se specificato specificando il nome, possono essere visualizzati in un ordine diverso da quello usato nella dichiarazione.
Gli argomenti denominati possono rendere il codice più leggibile e più adattabile a determinati tipi di modifiche nell'API, ad esempio un riordinamento dei parametri del metodo.
Gli argomenti denominati sono consentiti solo per i metodi, non per let
le funzioni associate, i valori delle funzioni o le espressioni lambda.
Nell'esempio di codice seguente viene illustrato l'uso di argomenti denominati.
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)
In una chiamata a un costruttore di classe è possibile impostare i valori delle proprietà della classe usando una sintassi simile a quella degli argomenti denominati. Nell'esempio seguente viene illustrata questa sintassi.
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)
Per altre informazioni, vedere Costruttori (F#).
La stessa tecnica, destinata a chiamare setter di proprietà, si applica anche a qualsiasi metodo che restituisce oggetti (ad esempio i metodi factory):
type Widget() =
member val Width = 1 with get,set
member val Height = 1 with get,set
type WidgetFactory =
static member MakeNewWidget() =
new Widget()
static member AdjustWidget(w: Widget) =
w
let w = WidgetFactory.MakeNewWidget(Width=10)
w.Width // = 10
w.Height // = 1
WidgetFactory.AdjustWidget(w, Height=10)
w.Height // = 10
Si noti che tali membri potrebbero eseguire qualsiasi lavoro arbitrario, la sintassi è in effetti una breve mano per chiamare setter di proprietà prima di restituire il valore finale.
Parametri facoltativi
È possibile specificare un parametro facoltativo per un metodo usando un punto interrogativo davanti al nome del parametro. I parametri facoltativi vengono interpretati come tipo di opzione F#, quindi è possibile eseguirne una query nel modo normale in cui vengono sottoposti a query i tipi di opzione usando un'espressione match
con Some
e None
. I parametri facoltativi sono consentiti solo sui membri, non sulle funzioni create tramite let
associazioni.
È possibile passare valori facoltativi esistenti al metodo in base al nome del parametro, ad esempio ?arg=None
o ?arg=Some(3)
o ?arg=arg
. Ciò può essere utile quando si compila un metodo che passa argomenti facoltativi a un altro metodo.
È anche possibile usare una funzione defaultArg
, che imposta un valore predefinito di un argomento facoltativo. La defaultArg
funzione accetta il parametro facoltativo come primo argomento e il valore predefinito come secondo.
Nell'esempio seguente viene illustrato l'uso di parametri facoltativi.
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)
let conn4 = Connection(?duplex0 = None)
let conn5 = Connection(?duplex0 = Some(Full))
let optionalDuplexValue : option<DuplexType> = Some(Half)
let conn6 = Connection(?duplex0 = optionalDuplexValue)
L'output è indicato di seguito.
Baud Rate: 9600 Duplex: Full Parity: false
Baud Rate: 4800 Duplex: Half Parity: false
Baud Rate: 300 Duplex: Half Parity: true
Baud Rate: 9600 Duplex: Full Parity: false
Baud Rate: 9600 Duplex: Full Parity: false
Baud Rate: 4800 Duplex: Half Parity: false
Ai fini dell'interoperabilità C# e Visual Basic è possibile usare gli attributi [<Optional; DefaultParameterValue<(...)>]
in F#, in modo che i chiamanti visualizzino un argomento come facoltativo. Equivale a definire l'argomento come facoltativo in C# come in MyMethod(int i = 3)
.
open System
open System.Runtime.InteropServices
type C =
static member Foo([<Optional; DefaultParameterValue("Hello world")>] message) =
printfn $"{message}"
È anche possibile specificare un nuovo oggetto come valore di parametro predefinito. Ad esempio, il Foo
membro potrebbe avere un facoltativo CancellationToken
come input:
open System.Threading
open System.Runtime.InteropServices
type C =
static member Foo([<Optional; DefaultParameterValue(CancellationToken())>] ct: CancellationToken) =
printfn $"{ct}"
Il valore specificato come argomento per DefaultParameterValue
deve corrispondere al tipo del parametro . Ad esempio, non è consentito quanto segue:
type C =
static member Wrong([<Optional; DefaultParameterValue("string")>] i:int) = ()
In questo caso, il compilatore genera un avviso e ignorerà completamente entrambi gli attributi. Si noti che il valore null
predefinito deve essere annotato come tipo, in caso contrario il compilatore deduce il tipo errato, ad esempio [<Optional; DefaultParameterValue(null:obj)>] o:obj
.
Passaggio per riferimento
Il passaggio di un valore F# per riferimento comporta byrefs, ovvero tipi di puntatore gestiti. Il materiale sussidiario per il tipo da usare è il seguente:
- Usare
inref<'T>
se è sufficiente leggere il puntatore. - Usare
outref<'T>
se è sufficiente scrivere nel puntatore. - Usare
byref<'T>
se è necessario leggere e scrivere nel puntatore.
let example1 (x: inref<int>) = printfn $"It's %d{x}"
let example2 (x: outref<int>) = x <- x + 1
let example3 (x: byref<int>) =
printfn $"It's %d{x}"
x <- x + 1
let test () =
// No need to make it mutable, since it's read-only
let x = 1
example1 &x
// Needs to be mutable, since we write to it
let mutable y = 2
example2 &y
example3 &y // Now 'y' is 3
Poiché il parametro è un puntatore e il valore è modificabile, tutte le modifiche apportate al valore vengono mantenute dopo l'esecuzione della funzione.
È possibile usare una tupla come valore restituito per archiviare tutti out
i parametri nei metodi della libreria .NET. In alternativa, è possibile considerare il out
parametro come byref
parametro. Nell'esempio di codice seguente vengono illustrati entrambi i modi.
// 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
Matrici di parametri
In alcuni casi è necessario definire una funzione che accetta un numero arbitrario di parametri di tipo eterogeneo. Non sarebbe pratico creare tutti i possibili metodi di overload per tenere conto di tutti i tipi che potrebbero essere usati. Le implementazioni di .NET forniscono supporto per tali metodi tramite la funzionalità della matrice di parametri. Un metodo che accetta una matrice di parametri nella relativa firma può essere fornito con un numero arbitrario di parametri. I parametri vengono inseriti in una matrice. Il tipo degli elementi della matrice determina i tipi di parametro che possono essere passati alla funzione. Se si definisce la matrice di parametri con System.Object
come tipo di elemento, il codice client può passare valori di qualsiasi tipo.
In F#, le matrici di parametri possono essere definite solo nei metodi. Non possono essere usati nelle funzioni autonome o nelle funzioni definite nei moduli.
Per definire una matrice di parametri, usare l'attributo ParamArray
. L'attributo ParamArray
può essere applicato solo all'ultimo parametro.
Il codice seguente illustra sia la chiamata di un metodo .NET che accetta una matrice di parametri che la definizione di un tipo in F# con un metodo che accetta una matrice di parametri.
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 viene eseguito in un progetto, l'output del codice precedente è il seguente:
a 1 10 Hello world 1 True
"a"
1
10.0
"Hello world"
1u
true
Vedi anche
Commenti e suggerimenti
https://aka.ms/ContentUserFeedback.
Presto disponibile: Nel corso del 2024 verranno gradualmente disattivati i problemi di GitHub come meccanismo di feedback per il contenuto e ciò verrà sostituito con un nuovo sistema di feedback. Per altre informazioni, vedereInvia e visualizza il feedback per