Partager via


Paramètres et arguments (F#)

Cette rubrique décrit comment le langage prend en charge la définition de paramètres et le passage d'arguments aux fonctions, aux méthodes et aux propriétés. Elle inclut des informations sur le passage par référence, et sur la définition et l'utilisation des méthodes qui peuvent prendre un nombre variable d'arguments.

Paramètres et arguments

Le terme paramètre est utilisé pour décrire les noms des valeurs censées être fournies. Le terme argument est utilisé désigner pour les valeurs fournies pour chaque paramètre.

Les paramètres peuvent être spécifiés sous forme de tuple ou sous forme curryfiée, ou dans une combinaison des deux. Vous pouvez passer des arguments à l'aide d'un nom de paramètre explicite. Vous pouvez spécifier les paramètres de méthodes comme étant facultatifs et leur attribuer une valeur par défaut.

Modèles de paramètre

En général, les paramètres fournis aux fonctions et aux méthodes sont des modèles séparés par des espaces. En principe, cela signifie que les modèles décrits dans Expressions match (F#) peuvent être utilisés dans une liste de paramètres pour une fonction ou un membre.

Les méthodes effectuent généralement le passage d'arguments sous forme de tuple. Cela permet d'obtenir des résultats plus clairs du point de vue d'autres langages .NET, car la forme de tuple correspond à la façon dont les arguments sont passés dans les méthodes .NET.

La forme curryfiée est la plus souvent utilisée avec des fonctions créées à l'aide de liaisons let.

Le pseudo-code suivant montre des exemples de tuple et d'arguments curryfiés.

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

Il est possible de combiner les formes lorsque certains arguments sont dans des tuples et que d'autres n'y sont pas.

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

Il est aussi possible d'utiliser d'autres modèles dans des listes de paramètres, mais si le modèle de paramètre ne correspond pas à toutes les entrées possibles, une correspondance incomplète peut se produire au moment de l'exécution. L'exception MatchFailureException est générée lorsque la valeur d'un argument ne correspond pas aux modèles spécifiés dans la liste de paramètres. Le compilateur émet un avertissement lorsqu'un modèle de paramètre accepte des correspondances incomplètes. Le modèle de caractère générique constitue un autre modèle communément utilisé pour les listes de paramètres. Vous pouvez utiliser le modèle de caractère générique dans une liste de paramètres lorsque vous voulez simplement ignorer tous les arguments fournis. Le code suivant illustre l'utilisation du modèle de caractère générique dans une liste d'arguments.

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

Le modèle de caractère générique peut être utile chaque fois que vous n'avez pas besoin des arguments passés, par exemple dans le point d'entrée principal d'un programme, ou lorsque vous ne vous intéressez pas aux arguments de ligne de commande fournis normalement en tant que tableau de chaînes, comme dans le code suivant.

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

Les autres modèles qui sont parfois utilisés dans des arguments sont le modèle as, et les modèles d'identificateur associés aux unions discriminées et aux modèles actifs. Vous pouvez utiliser le modèle d'union discriminée à un seul cas comme suit.

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

La sortie est la suivante.

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

Les modèles actifs peuvent être utiles comme paramètres, par exemple, en transformant un argument dans un format approprié, comme dans l'exemple suivant :

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

Vous pouvez utiliser le modèle as pour stocker une valeur correspondante comme valeur locale, comme indiqué dans la ligne de code suivante.

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

Un autre modèle utilisé parfois est une fonction qui laisse le dernier argument sans nom en fournissant, comme corps de la fonction, une expression lambda qui exécute immédiatement une correspondance de modèle sur l'argument implicite. La ligne de code suivante en donne une illustration.

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

Ce code définit une fonction qui prend une liste générique et qui retourne true si la liste est vide, et false dans le cas contraire. L'utilisation de telles techniques peut nuire à la lisibilité du code.

Parfois, les modèles qui impliquent des correspondances incomplètes sont utiles ; par exemple si vous savez que les listes dans votre programme ont uniquement trois éléments, vous pouvez utiliser un modèle comme le suivant dans une liste de paramètres.

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

L'utilisation de modèles avec des correspondances incomplètes est réservée au prototypage rapide et à d'autres utilisations temporaires. Le compilateur publiera un avertissement pour un tel code. De tels modèles ne peuvent pas couvrir le cas général de toutes les entrées possible et ne sont par conséquent pas appropriés pour les API de composant.

Arguments nommés

Les arguments de méthodes peuvent être spécifiés par position dans une liste d'arguments séparée par des virgules, ou passés explicitement à une méthode en fournissant le nom, suivis d'un signe égal et la valeur à passer. En cas de spécification en fournissant le nom, les arguments peuvent apparaître dans un ordre différent de celui utilisé dans la déclaration.

Les arguments nommés peuvent rendre le code plus lisible et plus adaptable à certains types de modifications dans l'API, notamment la réorganisation de paramètres de méthode.

Les arguments nommés sont uniquement autorisés dans les méthodes ; ils ne sont pas autorisés dans les fonctions liées à let, les valeurs de fonction ou les expressions lambda.

L'exemple de code suivant illustre l'utilisation d'arguments nommés.

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)

Dans un appel à un constructeur de classe, vous pouvez définir les valeurs des propriétés de la classe à l'aide d'une syntaxe semblable aux paramètres nommés. L'exemple suivant illustre cette syntaxe.

 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)

Pour plus d'informations, consultez Constructeurs (F#).

Paramètres optionnels

Vous pouvez spécifier un paramètre optionnel pour une méthode en utilisant un point d'interrogation devant le nom du paramètre. Les paramètres optionnels sont interprétés comme le type d'option F#. Vous pouvez donc les interroger de la même façon que les types d'option, en utilisant une expression match avec Some et None. Les paramètres optionnels sont autorisés uniquement sur les membres, et non sur les fonctions créées à l'aide de liaisons let.

Vous pouvez aussi utiliser une fonction defaultArg, qui définit la valeur par défaut d'un argument facultatif. La fonction defaultArg prend le paramètre facultatif comme premier argument et la valeur par défaut comme deuxième argument.

L'exemple suivant illustre l'utilisation de paramètres optionnels.

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)

La sortie est la suivante.

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

Passage par référence

F# prend en charge le mot clé byref, qui spécifie qu'un paramètre est passé par référence. Cela signifie que toutes les modifications apportées à la valeur sont conservées après l'exécution de la fonction. Les valeurs fournies à un paramètre byref doivent être mutables. Vous pouvez également passer des cellules de référence du type approprié.

Le passage par référence dans les langages .NET est devenu un moyen de retourner plusieurs valeurs à partir d'une fonction. En F#, vous pouvez retourner un tuple à cette fin ou utiliser une cellule de référence mutable en tant que paramètre. Le paramètre byref est fourni principalement à des fins d'interopérabilité avec les bibliothèques .NET.

L'exemple suivant illustre l'utilisation du mot clé byref. Notez que lorsque vous utilisez une cellule de référence comme paramètre, vous devez créer une cellule de référence comme valeur nommée et utiliser celle-ci comme paramètre. Vous ne pouvez pas vous contenter d'ajouter l'opérateur ref, comme indiqué dans le premier appel à Increment dans le code suivant. Étant donné que la création d'une cellule de référence crée une copie de la valeur sous-jacente, le premier appel incrémente simplement une valeur temporaire.

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  

Vous pouvez utiliser un tuple comme valeur de retour pour stocker des paramètres out dans des méthodes de la bibliothèque .NET. Vous pouvez également traiter le paramètre out comme paramètre byref. L'exemple de code suivant illustre les deux approches.

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

Tableaux de paramètres

Il est parfois nécessaire de définir une fonction qui prend un nombre arbitraire de paramètres de type hétérogène. Il serait peu judicieux de créer toutes les méthodes surchargées possibles pour prendre en compte tous les types pouvant être utilisés. La plateforme .NET assure la prise en charge de telles méthodes par l'intermédiaire de la fonctionnalité de tableau de paramètres. Une méthode qui prend un tableau de paramètres dans sa signature peut être fournie avec un nombre arbitraire de paramètres. Les paramètres sont placés dans un tableau. Le type des éléments de tableau détermine les types de paramètres qui peuvent être passés à la fonction. Si vous définissez le tableau de paramètres avec Object comme type d'élément, le code client peut passer des valeurs de n'importe quel type.

En F#, les tableaux de paramètres peuvent uniquement être définis dans des méthodes. Vous ne pouvez pas les utiliser dans des fonctions autonomes ou dans des fonctions définies dans des modules.

Pour définir un tableau de paramètres, utilisez l'attribut ParamArray. L'attribut ParamArray ne peut être appliqué qu'au dernier paramètre.

Le code suivant illustre l'appel à une méthode .NET qui prend un tableau de paramètres, ainsi que la définition d'un type en F# ayant une méthode qui prend un tableau de paramètres.

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

Lorsqu'il est exécuté dans un projet, la sortie du code précédent est la suivante :

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

Voir aussi

Autres ressources

Membres (F#)