Définir les valeurs par défaut des arguments de fonction

86

Dans le wiki Lua, j'ai trouvé un moyen de définir des valeurs par défaut pour les arguments manquants:

function myfunction(a,b,c)
    b = b or 7
    c = c or 5
    print (a,b,c)
end

Est-ce le seul moyen? Le style PHP myfunction (a,b=7,c=5)ne semble pas fonctionner. Non pas que la méthode Lua ne fonctionne pas, je me demande simplement si c'est la seule façon de le faire.

ripat
la source

Réponses:

86

Si vous voulez des arguments nommés et des valeurs par défaut comme PHP ou Python, vous pouvez appeler votre fonction avec un constructeur de table:

myfunction{a,b=3,c=2}

(Cela se voit dans de nombreux endroits dans Lua, comme les formes avancées des modules de protocole et des constructeurs de LuaSocket dans IUPLua .)

La fonction elle-même pourrait avoir une signature comme celle-ci:

function myfunction(t)
    setmetatable(t,{__index={b=7, c=5}})
    local a, b, c =
      t[1] or t.a, 
      t[2] or t.b,
      t[3] or t.c
    -- function continues down here...
end

Toute valeur manquante dans la table des paramètres sera extraite de la __indextable dans sa métatable (voir la documentation sur les métatables ).

Bien sûr, des styles de paramètres plus avancés sont possibles en utilisant des constructeurs et des fonctions de table - vous pouvez écrire tout ce dont vous avez besoin. Par exemple, voici une fonction qui construit une fonction qui prend des tables d'arguments nommés ou positionnels à partir d'une table définissant les noms de paramètres et les valeurs par défaut et une fonction prenant une liste d'arguments régulière.

En tant que fonctionnalité non au niveau du langage, ces appels peuvent être modifiés pour fournir de nouveaux comportements et sémantiques:

  • Les variables peuvent être amenées à accepter plusieurs noms
  • Les variables de position et les variables de mot-clé peuvent être intercalées - et définir les deux peut donner la priorité à l'un ou l'autre (ou provoquer une erreur)
  • Des variables sans position de mot-clé uniquement peuvent être créées, ainsi que des variables de position sans nom uniquement
  • La construction de table assez détaillée pourrait être effectuée en analysant une chaîne
  • La liste d'arguments peut être utilisée textuellement si la fonction est appelée avec autre chose qu'une table

Certaines fonctions utiles pour écrire des traducteurs d'arguments sont unpack(passage à table.unpacken 5.2), setfenv(obsolète en 5.2 avec la nouvelle _ENVconstruction), et select(qui renvoie une valeur unique à partir d'une liste d'arguments donnée, ou la longueur de la liste avec '#').

Stuart P. Bentley
la source
AI vient de commencer à utiliser lua, je vais rester simple pour le moment, mais votre message est très instructif. Cela pourrait être utile plus tard. Merci.
ripat
1
Dans la plupart des cas, rester simple est la voie à suivre. Les interfaces de méta-paramètres ne sont vraiment nécessaires que pour les objets avec un grand nombre d'attributs facultatifs (tels que les objets d'interface utilisateur).
Stuart P. Bentley
Je pense que cette réponse est celle qui résout les questions, pas celle actuellement marquée comme acceptée. Merci pour l'illumination :)
Annuler le
1
Il convient de noter que l' x or defaultexpression également utilisée dans cette réponse n'est pas vraiment un véritable équivalent aux paramètres par défaut, mais simplement une solution de contournement simpliste qui ne fonctionne que si les deux nilet falsesont des valeurs de paramètre non valides. Disons que la valeur par défaut pour un paramètre booléen xest trueet que l'appelant transmet un explicite false. Puis x or truedonne true, même si a falseété explicitement adopté. Une meilleure version serait if x == nil then x = default end, qui est également plus lisible; il ne peut toujours pas gérer les nilarguments explicites .
Jesper
Oh, hé, c'est la réponse acceptée maintenant! Agréable. (Pour mémoire, et pour mettre en contexte le commentaire de @ Undo, la réponse de jpjacobs ci-dessous a été la réponse acceptée pendant très longtemps: j'ai failli avoir un deuxième badge populiste dessus.)
Stuart P. Bentley
46

À mon avis, il n'y a pas d'autre moyen. C'est juste la mentalité Lua: pas de fioritures, et à l'exception de quelques sucres syntaxiques, pas de façons redondantes de faire des choses simples.

jpjacobs
la source
10
Cette réponse est complètement réfutée par la réponse de Stuart P. Bentley ci-dessous, dans laquelle la fonction est appelée avec un constructeur de table. C'est l'une des forces de Lua: bien qu'il n'ait pas beaucoup de fioritures, les blocs de construction fondamentaux de Lua vous permettent de faire des choses illimitées, vraiment remarquables par la petite taille et la simplicité de la langue.
Colin D Bennett
@ColinDBennett Merci d'avoir pris la parole: il semblerait que l'OP ait lu votre commentaire et, en décembre, a changé la réponse acceptée en conséquence. (Et maintenant c'est "la réponse de Stuart P. Bentley ci-dessus", pour plus de clarté: wink :)
Stuart P. Bentley
21

Techniquement, il y a b = b == nil and 7 or b(qui devrait être utilisé dans le cas où falseune valeur valide est false or 7évaluée à 7), mais ce n'est probablement pas ce que vous recherchez.

Stuart P. Bentley
la source
1
Si vous ne recherchez pas false, un moyen plus simple consiste à placer la variable en premier et la valeur par défaut en dernier. b = b or 7
Rebs
2
Puisque l'OP a mentionné cela dans sa question, j'ai pensé qu'il serait superflu de le mentionner (la question portait sur les moyens de définir des variables par défaut autres que b = b or 7 ).
Stuart P. Bentley
6

Le seul moyen que j'ai trouvé jusqu'à présent qui ait du sens est de faire quelque chose comme ceci:

function new(params)
  params = params or {}
  options = {
    name = "Object name"
  }

  for k,v in pairs(params) do options[k] = v end

  some_var = options.name
end

new({ name = "test" })
new()
NeufAveuglesYeux
la source