Share via


Paraméterek és argumentumok

Ez a témakör a paraméterek definiálásának és az argumentumok függvényeknek, metódusoknak és tulajdonságoknak való átadásának nyelvi támogatását ismerteti. Információkat tartalmaz arról, hogyan adhat át hivatkozás alapján, és hogyan definiálhat és használhat olyan metódusokat, amelyek változó számú argumentumot tartalmazhatnak.

Paraméterek és argumentumok

A kifejezésparaméter a várhatóan megadandó értékek nevét írja le. A kifejezés argumentum az egyes paraméterekhez megadott értékekhez használatos.

A paraméterek megadhatók tuple vagy curried formában, vagy a kettő valamilyen kombinációjában. Az argumentumokat explicit paraméternévvel adhatja át. A metódusok paraméterei megadhatóak választhatóként, és megadhatnak egy alapértelmezett értéket.

Paraméterminták

A függvényekhez és metódusokhoz megadott paraméterek általában szóközökkel elválasztott minták. Ez azt jelenti, hogy a Match Expressionsben leírt minták elvileg használhatók egy függvény vagy tag paraméterlistájában.

A metódusok általában az átadott argumentumok rekordformájú formáját használják. Ez egyértelműbb eredményt ad más .NET-nyelvek szempontjából, mivel a rekordforma megegyezik az argumentumok .NET-metódusokban való átadásának módjával.

A curried űrlapot leggyakrabban kötések használatával let létrehozott függvényekkel használják.

Az alábbi pszeudokód példákat mutat be a rekord- és a curriált argumentumokra.

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

A kombinált űrlapok akkor lehetségesek, ha egyes argumentumok össze vannak kötve, és vannak, amelyek nem.

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

A paraméterlistákban más minták is használhatók, de ha a paraméterminta nem felel meg az összes lehetséges bemenetnek, előfordulhat, hogy a futtatáskor hiányos egyezés van. A kivétel MatchFailureException akkor jön létre, ha egy argumentum értéke nem egyezik a paraméterlistában megadott mintákkal. A fordító figyelmeztetést ad ki, ha egy paraméterminta lehetővé teszi a hiányos egyezéseket. Legalább egy másik minta gyakran hasznos paraméterlistákhoz, és ez a helyettesítő karakterminta. A helyettesítő karakterek mintáját akkor használja egy paraméterlistában, ha egyszerűen figyelmen kívül szeretné hagyni a megadott argumentumokat. Az alábbi kód egy argumentumlistában szemlélteti a helyettesítő karakterek használatát.

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

A helyettesítő karakterminta akkor lehet hasznos, ha nincs szüksége a programnak átadott argumentumokra, például a fő belépési pontban, ha nem érdeklik a sztringtömbként általában megadott parancssori argumentumok, mint az alábbi kódban.

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

Az argumentumokban néha használt egyéb minták a minta, valamint a as diszkriminált egyesítőkhöz és az aktív mintákhoz társított azonosító minták. Az egy-eseti diszkriminált egyesítő mintát az alábbiak szerint használhatja.

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 kimenet a következő.

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

Az aktív minták paraméterekként hasznosak lehetnek, például amikor egy argumentumot kívánt formátummá alakítanak át, ahogyan az alábbi példában is látható:

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

A mintával as helyi értékként tárolhat egy egyeztetett értéket, ahogy az az alábbi kódsorban is látható.

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

Az időnként használt másik minta egy olyan függvény, amely az utolsó argumentumot névtelenül hagyja, mivel a függvény törzseként egy lambda kifejezést ad meg, amely azonnal végrehajt egy mintaegyezést az implicit argumentumon. Erre példa a következő kódsor.

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

Ez a kód egy olyan függvényt határoz meg, amely egy általános listát vesz fel, és akkor ad vissza true , ha a lista üres, és false egyébként. Az ilyen technikák használata megnehezítheti a kód olvasását.

Időnként hasznosnak bizonyulhatnak a hiányos egyezéseket tartalmazó minták, például ha tudja, hogy a program listáinak csak három eleme van, akkor egy paraméterlistában az alábbihoz hasonló mintát használhat.

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

A hiányos egyezésekkel rendelkező minták használata a legjobban a gyors prototípus-készítéshez és más ideiglenes használatra van fenntartva. A fordító figyelmeztetést ad ki az ilyen kódhoz. Az ilyen minták nem fedik le az összes lehetséges bemenet általános esetét, ezért nem alkalmasak az összetevő API-k használatára.

Névvel ellátott argumentumok

A metódusok argumentumai vesszővel tagolt argumentumlistában elfoglalt pozíció alapján határozhatók meg, vagy explicit módon továbbíthatók egy metódusnak a név megadásával, majd egy egyenlőségjellel és az átadandó értékkel. Ha a név megadásával van megadva, a deklarációban használttól eltérő sorrendben jelenhetnek meg.

Az elnevezett argumentumok a kód olvashatóbbá és könnyebben módosíthatóvá tehetik az API bizonyos módosításait, például a metódusparaméterek átrendezését.

A névvel ellátott argumentumok csak metódusok esetén engedélyezettek, nem letpedig -bound függvényekhez, függvényértékekhez vagy lambdakifejezésekhez.

Az alábbi példakód az elnevezett argumentumok használatát mutatja be.

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)

Egy osztálykonstruktor hívásában az osztály tulajdonságainak értékeit az elnevezett argumentumokhoz hasonló szintaxissal állíthatja be. Az alábbi példa ezt a szintaxist mutatja be.

 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)

További információt a Konstruktorok (F#) című témakörben talál.

Ugyanez a módszer, amely a tulajdonsághalmazok meghívására szolgál, minden objektumvisszaadó metódusra (például a gyári metódusokra) is vonatkozik:

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

Vegye figyelembe, hogy ezek a tagok tetszőleges munkát végezhetnek, a szintaxis gyakorlatilag egy rövid kéz a tulajdonsághalmazok meghívásához a végső érték visszaadása előtt.

Opcionális paraméterek

Egy metódus opcionális paraméterét a paraméter neve előtti kérdőjel használatával adhatja meg. A választható paramétereket az F# beállítástípusként értelmezi a rendszer, így a lekérdezésük szokásos módon történik a beállítástípusok lekérdezésében egy kifejezés és SomeNoneegy match . Az opcionális paraméterek csak tagokon engedélyezettek, kötések használatával let létrehozott függvényeken nem.

A meglévő opcionális értékeket paraméternév alapján adhat át a metódusnak, például ?arg=None vagy ?arg=arg?arg=Some(3) . Ez akkor lehet hasznos, ha olyan metódust hoz létre, amely az opcionális argumentumokat egy másik metódusnak adja át.

Használhat olyan függvényt defaultArgis, amely egy opcionális argumentum alapértelmezett értékét állítja be. A defaultArg függvény az opcionális paramétert első argumentumként, az alapértelmezett értéket pedig másodikként veszi fel.

Az alábbi példa az opcionális paraméterek használatát mutatja be.

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)

A kimenet a következő.

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

A C# és a Visual Basic interop esetében az F# attribútumait [<Optional; DefaultParameterValue<(...)>] használhatja, így a hívók egy argumentumot nem kötelezőként fognak látni. Ez egyenértékű azzal, hogy az argumentumot nem kötelezőként definiálja a C# fájlban, mint a következőben MyMethod(int i = 3).

open System
open System.Runtime.InteropServices
type C =
    static member Foo([<Optional; DefaultParameterValue("Hello world")>] message) =
        printfn $"{message}"

Megadhat egy új objektumot is alapértelmezett paraméterértékként. Előfordulhat például, hogy a Foo tag nem kötelező CancellationToken bemenetként:

open System.Threading
open System.Runtime.InteropServices
type C =
    static member Foo([<Optional; DefaultParameterValue(CancellationToken())>] ct: CancellationToken) =
        printfn $"{ct}"

Az argumentumként megadott értéknek DefaultParameterValue meg kell egyeznie a paraméter típusával. A következők például nem engedélyezettek:

type C =
    static member Wrong([<Optional; DefaultParameterValue("string")>] i:int) = ()

Ebben az esetben a fordító figyelmeztetést hoz létre, és teljesen figyelmen kívül hagyja mindkét attribútumot. Vegye figyelembe, hogy az alapértelmezett értéket null gépelt jegyzetekkel kell megadni, ellenkező esetben a fordító nem a megfelelő típust, azaz [<Optional; DefaultParameterValue(null:obj)>] o:obj.

Továbbítás hivatkozás alapján

Az F#-érték hivatkozás alapján történő átadása byrefs-eket is magában foglal, amelyek felügyelt mutatótípusok. Útmutatás a használni kívánt típushoz:

  • Akkor használja inref<'T> , ha csak a mutatót kell elolvasnia.
  • Akkor használja outref<'T> , ha csak az egérmutatóra kell írnia.
  • Akkor használja byref<'T> , ha egyszerre kell olvasnia és írnia az egérmutatóra.
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

Mivel a paraméter egy mutató, és az érték nem módosítható, az érték módosításai a függvény végrehajtása után is megmaradnak.

A rekordokat visszatérési értékként használhatja a out paraméterek .NET-kódtár-metódusokban való tárolásához. Másik lehetőségként paraméterként is kezelheti a out paramétert byref . Az alábbi példakód mindkét módszert szemlélteti.

// 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

Paramétertömbök

Időnként meg kell határozni egy függvényt, amely tetszőleges számú heterogén típusú paramétert vesz igénybe. Nem lenne célszerű létrehozni az összes lehetséges túlterhelt metódust, hogy figyelembe lehessen venni az összes használható típust. A .NET-implementációk a paramétertömb funkcióval támogatják az ilyen metódusokat. Az aláírásban egy paramétertömböt használó metódus tetszőleges számú paramétert adhat meg. A paraméterek egy tömbbe kerülnek. A tömbelemek típusa határozza meg a függvénynek továbbítható paramétertípusokat. Ha elemtípusként definiálja a paramétertömböt System.Object , az ügyfélkód bármilyen típusú értéket átadhat.

Az F#-ban a paramétertömbök csak metódusokban definiálhatók. Nem használhatók önálló függvényekben vagy modulokban definiált függvényekben.

Paramétertömböt az ParamArray attribútum használatával definiálhat. Az ParamArray attribútum csak az utolsó paraméterre alkalmazható.

Az alábbi kód egy paramétertömböt használó .NET-metódus meghívását és egy paramétertömböt használó metódust tartalmazó F# típus definícióját mutatja be.

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

Projektben való futtatáskor az előző kód kimenete a következő:

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

Lásd még