Defina os valores padrão para os argumentos da função

86

No Lua wiki, encontrei uma maneira de definir valores padrão para argumentos ausentes:

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

Este é o único caminho? O estilo PHP myfunction (a,b=7,c=5)parece não funcionar. Não que o jeito Lua não funcione, só estou me perguntando se essa é a única maneira de fazer isso.

ripat
fonte

Respostas:

86

Se quiser argumentos nomeados e valores padrão como PHP ou Python, você pode chamar sua função com um construtor de tabela:

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

(Isso é visto em muitos lugares em Lua, como as formas avançadas dos módulos de protocolo e construtores de LuaSocket em IUPLua .)

A própria função pode ter uma assinatura 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

Quaisquer valores ausentes na tabela de parâmetros serão retirados da __indextabela em sua meta-tabela (consulte a documentação sobre meta-tabelas ).

Claro, estilos de parâmetros mais avançados são possíveis usando construtores e funções de tabela - você pode escrever o que precisar. Por exemplo, aqui está uma função que constrói uma função que obtém tabelas de argumentos nomeados ou posicionais de uma tabela que define os nomes dos parâmetros e valores padrão e uma função que obtém uma lista de argumentos regulares.

Como um recurso não relacionado ao idioma, essas chamadas podem ser alteradas para fornecer novos comportamentos e semânticas:

  • As variáveis ​​podem ser feitas para aceitar mais de um nome
  • Variáveis ​​posicionais e variáveis ​​de palavras-chave podem ser intercaladas - e definir ambas pode dar precedência a qualquer uma (ou causar um erro)
  • Podem ser criadas variáveis ​​sem posição apenas com palavras-chave, bem como variáveis ​​apenas com posição sem nome
  • A construção da tabela bastante detalhada pode ser feita analisando uma string
  • A lista de argumentos pode ser usada literalmente se a função for chamada com algo diferente de 1 tabela

Algumas funções úteis para escrever tradutores de argumento são unpack(mudando para table.unpack5.2), setfenv(obsoleto em 5.2 com a nova _ENVconstrução) e select(que retorna um único valor de uma determinada lista de argumentos, ou o comprimento da lista com '#').

Stuart P. Bentley
fonte
AI apenas comecei a usar lua Vou mantê-lo simples para o momento, mas sua postagem é muito informativa. Pode ser útil mais tarde. Obrigado.
ripat
1
Na maioria dos casos, manter a simplicidade é o caminho a percorrer. As interfaces de meta-parâmetros são realmente necessárias apenas para objetos com um grande número de atributos opcionais (como objetos de IU).
Stuart P. Bentley
Acho que essa resposta é quem resolve as questões, não aquela atualmente marcada como aceita. Obrigado pela iluminação :)
Desfazer em
1
Deve-se observar que a x or defaultexpressão também usada nesta resposta não é realmente um equivalente verdadeiro aos padrões de parâmetro, mas apenas uma solução simplista que só funciona se ambos nile falseforem valores de parâmetro inválidos. Digamos que o padrão para um parâmetro booleano xé truee o chamador passa um explícito false. Em seguida , x or truetrue, mesmo que tenha falsesido explicitamente passado. Uma versão melhor seria if x == nil then x = default end, que também é mais legível; ele ainda não consegue lidar com nilargumentos explícitos .
Jesper
Oh, ei, esta é a resposta aceita agora! Agradável. (Para registro, e para colocar o comentário de @Undo no contexto, a resposta de jpjacobs abaixo foi aceita por muito tempo: quase ganhei um segundo emblema populista por ele.)
Stuart P. Bentley
46

Na minha opinião não existe outra maneira. Essa é apenas a mentalidade da Lua: sem frescuras e, exceto por um pouco de açúcar sintático, sem maneiras redundantes de fazer coisas simples.

jpjacobs
fonte
10
Essa resposta é completamente refutada pela resposta de Stuart P. Bentley abaixo, em que a função é chamada com um construtor de tabela. Este é um dos pontos fortes da Lua: embora não tenha um monte de babados, os blocos de construção fundamentais da Lua permitem que você faça coisas ilimitadas, verdadeiramente notável pelo tamanho pequeno e pela simplicidade da linguagem.
Colin D Bennett
@ColinDBennett Obrigado por se manifestar: parece que o OP leu seu comentário e, naquele dezembro, alterou a resposta aceita de acordo. (E agora é "a resposta de Stuart P. Bentley acima", para fins de clareza: wink :)
Stuart P. Bentley
21

Tecnicamente, há b = b == nil and 7 or b(que deve ser usado no caso em que falseé um valor válido quando false or 7avaliado em 7), mas provavelmente não é o que você está procurando.

Stuart P. Bentley
fonte
1
Se você não estiver verificando false, uma maneira mais simples é colocar a variável primeiro e o padrão por último. b = b or 7
Rebs
2
Uma vez que o OP mencionou que em sua pergunta, eu imaginei que seria supérfluo mencionar (a pergunta foi sobre formas de definir variáveis padrão diferente b = b or 7 ).
Stuart P. Bentley
6

A única maneira que descobri até agora que faz algum sentido é fazer algo assim:

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()
NineBlindEyes
fonte