Definir valores predeterminados para argumentos de función

86

En la wiki de Lua encontré una forma de definir valores predeterminados para los argumentos faltantes:

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

¿Es esa la única forma? El estilo PHP myfunction (a,b=7,c=5)no parece funcionar. No es que la forma Lua no funcione, solo me pregunto si esta es la única forma de hacerlo.

ripat
fuente

Respuestas:

86

Si desea argumentos con nombre y valores predeterminados como PHP o Python, puede llamar a su función con un constructor de tabla:

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

(Esto se ve en muchos lugares de Lua, como las formas avanzadas de los módulos y constructores de protocolo de LuaSocket en IUPLua ).

La función en sí podría tener una firma como esta:

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

Cualquier valor que falte en la tabla de parámetros se tomará de la __indextabla en su metatabla (consulte la documentación sobre metatablas ).

Por supuesto, los estilos de parámetros más avanzados son posibles usando constructores de tablas y funciones; puede escribir lo que necesite. Por ejemplo, aquí hay una función que construye una función que toma tablas de argumentos con nombre o posicionales de una tabla que define los nombres de los parámetros y los valores predeterminados y una función que toma una lista de argumentos normal.

Como característica que no es del nivel del idioma, estas llamadas se pueden cambiar para proporcionar nuevos comportamientos y semánticas:

  • Se pueden hacer variables para aceptar más de un nombre
  • Las variables de posición y las variables de palabras clave se pueden intercalar, y la definición de ambas puede dar prioridad a cualquiera de las dos (o provocar un error)
  • Se pueden crear variables sin posición de solo palabras clave, así como variables de solo posición sin nombre
  • La construcción de la tabla bastante detallada se puede realizar analizando una cadena
  • La lista de argumentos podría usarse literalmente si la función se llama con algo diferente a 1 tabla

Algunas funciones útiles para escribir traductores de argumentos son unpack(pasando a table.unpack5.2), setfenv(en desuso en 5.2 con la nueva _ENVconstrucción) y select(que devuelve un solo valor de una lista de argumentos dada, o la longitud de la lista con '#').

Stuart P. Bentley
fuente
AI acaba de comenzar a usar lua. Lo mantendré simple por el momento, pero su publicación es muy informativa. Podría ser útil más adelante. Gracias.
ripat
1
En la mayoría de los casos, hacerlo simple es el camino a seguir. Las interfaces de metaparámetros solo son realmente necesarias para objetos con una gran cantidad de atributos opcionales (como los objetos UI).
Stuart P. Bentley
Creo que esta respuesta es la que resuelve las preguntas, no la marcada actualmente como aceptada. Gracias por la iluminación :)
Deshacer
1
Cabe señalar que la x or defaultexpresión que también se usa en esta respuesta no es realmente un verdadero equivalente a los valores predeterminados de los parámetros, sino solo una solución simplista que solo funciona si ambos nily falseson valores de parámetro no válidos. Digamos que el valor predeterminado para un parámetro booleano xes truey el llamador pasa un explícito false. Luego x or truecede true, aunque falsese pasó explícitamente. Una mejor versión sería if x == nil then x = default end, que también es más legible; aunque todavía no puede manejar nilargumentos explícitos .
Jesper
¡Oh, oye, esta es la respuesta aceptada ahora! Agradable. (Para el registro, y para poner el comentario de @ Undo en contexto, la respuesta de jpjacobs a continuación fue la respuesta aceptada durante mucho tiempo: casi obtengo una segunda insignia populista sobre ella.)
Stuart P. Bentley
46

En mi opinión, no hay otra forma. Esa es solo la mentalidad de Lua: sin lujos y, excepto por un poco de azúcar sintáctico, sin formas redundantes de hacer cosas simples.

jpjacobs
fuente
10
Esta respuesta está completamente refutada por la respuesta de Stuart P. Bentley a continuación, en la que la función se llama con un constructor de tabla. Este es uno de los puntos fuertes de Lua: si bien no tiene muchos lujos, los bloques de construcción fundamentales de Lua te permiten hacer cosas ilimitadas, realmente notables por el tamaño pequeño y la simplicidad del lenguaje.
Colin D Bennett
@ColinDBennett Gracias por hablar: parece que el OP leyó su comentario y, en diciembre, cambió la respuesta aceptada en consecuencia. (Y ahora es la "respuesta de Stuart P. Bentley arriba", por el bien de la claridad: guiño :)
Stuart P. Bentley
21

Técnicamente, hay b = b == nil and 7 or b(que debería usarse en el caso de que falsehaya un valor válido que se false or 7evalúe como 7), pero probablemente no sea lo que está buscando.

Stuart P. Bentley
fuente
1
Si no está buscando false, una forma más sencilla es poner la variable primero y la predeterminada al final. b = b or 7
Rebs
2
Dado que el OP mencionó eso en su pregunta, pensé que sería superfluo mencionarlo (la pregunta era sobre formas de definir variables predeterminadas distintas de b = b or 7 ).
Stuart P. Bentley
6

La única forma que he encontrado hasta ahora que tiene sentido es hacer algo como esto:

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()
NineBlindOjos
fuente