Parametry a argumenty
Toto téma popisuje podporu jazyka pro definování parametrů a předávání argumentů funkcím, metodám a vlastnostem. Obsahuje informace o tom, jak předávat odkazy a jak definovat a používat metody, které mohou mít proměnlivý počet argumentů.
Parametry a argumenty
Parametr termínu slouží k popisu názvů hodnot, u které se očekává, že se mají zadávat. Argument termínu se používá pro hodnoty zadané pro každý parametr.
Parametry je možné zadat ve formě řazené kolekce členů nebo ve složené podobě nebo v některé kombinaci těchto dvou. Argumenty můžete předat pomocí explicitního názvu parametru. Parametry metod lze zadat jako volitelné a zadat výchozí hodnotu.
Vzory parametrů
Parametry poskytované funkcím a metodám jsou obecně vzory oddělené mezerami. To znamená, že v zásadě lze některý ze vzorů popsaných ve výrazech shody použít v seznamu parametrů pro funkci nebo člena.
Metody obvykle používají formu řazené kolekce členů předávacích argumentů. Tím dosáhnete jasnějšího výsledku z pohledu jiných jazyků .NET, protože formulář řazené kolekce členů odpovídá způsobu předávání argumentů v metodách .NET.
Složený formulář se nejčastěji používá s funkcemi vytvořenými pomocí let
vazeb.
Následující pseudokód ukazuje příklady řazené kolekce členů a složených argumentů.
// Tuple form.
member this.SomeMethod(param1, param2) = ...
// Curried form.
let function1 param1 param2 = ...
Kombinované formuláře jsou možné, pokud jsou některé argumenty v řazených kolekcích členů a některé ne.
let function2 param1 (param2a, param2b) param3 = ...
Další vzory lze použít také v seznamech parametrů, ale pokud vzor parametrů neodpovídá všem možným vstupům, může být v době běhu neúplná shoda. Výjimka MatchFailureException
se vygeneruje, pokud hodnota argumentu neodpovídá vzorům zadaným v seznamu parametrů. Kompilátor vydá upozornění, když vzor parametrů umožňuje nekompletní shody. Nejméně jeden jiný vzor je běžně užitečný pro seznamy parametrů a to je zástupný znak. Vzor se zástupnými důkazy v seznamu parametrů použijete, když chcete jednoduše ignorovat všechny zadané argumenty. Následující kód znázorňuje použití vzoru se zástupnými znaky v seznamu argumentů.
let makeList _ = [ for i in 1 .. 100 -> i * i ]
// The arguments 100 and 200 are ignored.
let list1 = makeList 100
let list2 = makeList 200
Vzorec se zástupnými znaky může být užitečný vždy, když nepotřebujete předané argumenty, například v hlavním vstupním bodě programu, pokud nemáte zájem o argumenty příkazového řádku, které jsou obvykle zadány jako pole řetězců, jako v následujícím kódu.
[<EntryPoint>]
let main _ =
printfn "Entry point!"
0
Jiné vzory, které se někdy používají v argumentech, jsou as
vzor a vzory identifikátorů spojené s diskriminovanými sjednoceními a aktivními vzory. Model sjednocovacího sjednocení s jedním případem můžete použít následujícím způsobem.
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
Výstup je následující.
Data begins at 0 and ends at 4 in string Et tu, Brute?
Et tu
Aktivní vzory můžou být užitečné například jako parametry, například při transformaci argumentu do požadovaného formátu, jako v následujícím příkladu:
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
Vzor můžete použít as
k uložení odpovídající hodnoty jako místní hodnoty, jak je znázorněno na následujícím řádku kódu.
let GetSubstring2 (Slice(p0, p1, text) as s) = s
Dalším vzorem, který se používá příležitostně, je funkce, která ponechá poslední argument nepojmenovaný tak, že jako tělo funkce poskytne výraz lambda, který okamžitě provede shodu vzoru u implicitního argumentu. Příkladem je následující řádek kódu.
let isNil = function [] -> true | _::_ -> false
Tento kód definuje funkci, která vezme obecný seznam a vrátí true
, pokud je seznam prázdný, a false
v opačném případě. Použití těchto technik může ztížit čtení kódu.
Vzory, které zahrnují neúplné shody, jsou někdy užitečné, například pokud víte, že seznamy v programu mají pouze tři prvky, můžete použít vzor podobný následujícímu v seznamu parametrů.
let sum [a; b; c;] = a + b + c
Použití vzorů, které mají neúplné shody, je nejvhodnější pro rychlé vytváření prototypů a další dočasná použití. Kompilátor vydá pro takový kód upozornění. Tyto vzory nemohou pokrýt obecný případ všech možných vstupů, a proto nejsou vhodné pro rozhraní API součástí.
Pojmenované argumenty
Argumenty pro metody lze zadat podle pozice v seznamu argumentů oddělených čárkami, nebo mohou být předány metodě explicitně zadáním názvu, následovaného znaménkem rovná se a hodnotou, která se má předat. Pokud je zadaný zadáním názvu, může se zobrazit v jiném pořadí, než který se použil v deklaraci.
Pojmenované argumenty můžou kód lépe čitelný a lépe přizpůsobitelný určitým typům změn v rozhraní API, jako je například změna pořadí parametrů metody.
Pojmenované argumenty jsou povoleny pouze pro metody, ne pro let
výrazy lambda, funkce, hodnoty funkce nebo výrazy lambda.
Následující příklad kódu ukazuje použití pojmenovaných argumentů.
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)
Při volání konstruktoru třídy můžete nastavit hodnoty vlastností třídy pomocí syntaxe podobné syntaxi pojmenovaných argumentů. Následující příklad ukazuje tuto syntaxi.
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)
Další informace naleznete v tématu Konstruktory (F#).
Stejná technika, která má volat vlastnosti setters, platí také pro jakoukoli metodu vrácení objektu (například metody továrny):
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
Všimněte si, že tito členové mohou provádět libovolnou práci, syntaxe je v podstatě krátká ruka pro volání setter vlastností před vrácením konečné hodnoty.
Volitelné parametry
Volitelný parametr pro metodu můžete zadat pomocí otazníku před názvem parametru. Z pohledu volaného se volitelné parametry interpretují jako typ možnosti jazyka F#, takže je můžete dotazovat běžným způsobem, jakým jsou typy možností dotazovány, pomocí výrazu match
s Some
a None
. Volitelné parametry jsou povoleny pouze pro členy, ne pro funkce vytvořené pomocí let
vazeb.
Existující volitelné hodnoty můžete předat metodě podle názvu parametru, například ?arg=None
nebo ?arg=Some(3)
?arg=arg
. To může být užitečné při vytváření metody, která předává volitelné argumenty jiné metodě.
Můžete také použít funkci defaultArg
, která nastaví výchozí hodnotu volitelného argumentu. Funkce defaultArg
přebírá volitelný parametr jako první argument a výchozí hodnotu jako druhou.
Následující příklad ukazuje použití volitelných parametrů.
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)
Výstup je následující.
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
Pro účely zprostředkovatele komunikace jazyka C# a Visual Basic můžete použít atributy [<Optional; DefaultParameterValue<(...)>]
v jazyce F#, aby volající viděli argument jako nepovinný. To je ekvivalentem definování argumentu jako volitelného v jazyce C# jako v MyMethod(int i = 3)
jazyce .
open System
open System.Runtime.InteropServices
type C =
static member Foo([<Optional; DefaultParameterValue("Hello world")>] message) =
printfn $"{message}"
Nový objekt můžete také zadat jako výchozí hodnotu parametru. Člen může mít například Foo
volitelný CancellationToken
vstup jako vstup:
open System.Threading
open System.Runtime.InteropServices
type C =
static member Foo([<Optional; DefaultParameterValue(CancellationToken())>] ct: CancellationToken) =
printfn $"{ct}"
Hodnota zadaná jako argument DefaultParameterValue
musí odpovídat typu parametru. Například následující možnosti nejsou povoleny:
type C =
static member Wrong([<Optional; DefaultParameterValue("string")>] i:int) = ()
V tomto případě kompilátor vygeneruje upozornění a bude ignorovat oba atributy úplně. Všimněte si, že výchozí hodnota null
musí být typu anotována, protože jinak kompilátor odvodí nesprávný typ, tj. [<Optional; DefaultParameterValue(null:obj)>] o:obj
.
Předávání podle odkazu
Předání hodnoty jazyka F# odkazem zahrnuje odkazy na odkazy, což jsou spravované typy ukazatelů. Pokyny pro typ, který se má použít, jsou následující:
- Použijte
inref<'T>
, pokud potřebujete jen přečíst ukazatel. - Použijte
outref<'T>
, pokud potřebujete na ukazatel psát pouze. - Použijte
byref<'T>
, pokud potřebujete číst z ukazatele i zapisovat do ukazatele.
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
Vzhledem k tomu, že parametr je ukazatel a hodnota je proměnlivá, všechny změny hodnoty se zachovají po spuštění funkce.
Řazenou kolekci členů můžete použít jako návratovou hodnotu k uložení libovolných out
parametrů v metodách knihovny .NET. Případně můžete s parametrem zacházet out
jako s parametrem byref
. Následující příklad kódu ukazuje oba způsoby.
// 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
Pole parametrů
Někdy je nutné definovat funkci, která přebírá libovolný počet parametrů heterogenního typu. Není praktické vytvořit všechny možné přetížené metody, které by zohlednily všechny typy, které by bylo možné použít. Implementace .NET poskytují podporu těchto metod prostřednictvím funkce pole parametrů. Metodu, která přebírá pole parametrů v podpisu, lze poskytnout libovolný počet parametrů. Parametry jsou vloženy do pole. Typ prvků pole určuje typy parametrů, které lze předat funkci. Pokud definujete pole parametrů jako System.Object
typ elementu, klientský kód může předat hodnoty libovolného typu.
V jazyce F# lze pole parametrů definovat pouze v metodách. Nelze je použít v samostatných funkcích nebo funkcích definovaných v modulech.
Pomocí atributu ParamArray
definujete pole parametrů. Atribut ParamArray
lze použít pouze u posledního parametru.
Následující kód znázorňuje volání metody .NET, která přebírá pole parametrů a definici typu v jazyce F#, která má metodu, která přebírá pole parametrů.
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
Při spuštění v projektu je výstup předchozího kódu následující:
a 1 10 Hello world 1 True
"a"
1
10.0
"Hello world"
1u
true