定义函数参数的默认值


86

在Lua Wiki中,我找到了一种定义缺少参数的默认值的方法:

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

那是唯一的方法吗?PHP样式myfunction (a,b=7,c=5)似乎无效。并不是说Lua方法行不通,我只是想知道这是否是唯一的方法。

Answers:


86

如果需要命名参数和默认值(例如PHP或Python),则可以使用表构造函数调用函数:

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

(这在Lua的很多地方都可以看到,例如LuaSocket协议模块的高级形式和IUPLua中的构造函数。)

函数本身可以具有如下签名:

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

参数表中缺少的任何值都将从__index其元表中的表中获取(请参阅有关metatables的文档)。

当然,使用表构造函数和函数可以使用更高级的参数样式-您可以编写所需的任何内容。例如,这里的函数构造一个函数,该函数从定义参数名称和默认值的表中获取命名或位置参数表,以及一个带有常规参数列表的函数。

作为非语言级别的功能,可以更改此类调用以提供新的行为和语义:

  • 可以使变量接受多个名称
  • 位置变量和关键字变量可以散布-定义两者可以赋予其中一个优先级(或导致错误)
  • 可以创建仅关键字的无位置变量,以及无名称的仅位置变量
  • 相当详细的表构造可以通过解析字符串来完成
  • 如果用1个表以外的函数调用函数,则可以逐字使用参数列表

编写自变量转换器的一些有用函数是unpacktable.unpack在5.2中移至),setfenv(在5.2中使用新_ENV结构弃用)和select(从给定参数列表返回单个值,或使用返回列表的长度'#')。


AI刚刚开始使用lua,我会暂时简化它,但是您的帖子内容非常丰富。以后可能会派上用场。谢谢。
11

1
在大多数情况下,保持简单是必经之路。只有具有大量可选属性的对象(例如UI对象)才真正需要元参数接口。
Stuart P. Bentley,

我认为此答案是解决问题的答案,而不是当前标记为已接受的答案。感谢您的启发:)
撤消

1
应该注意的是x or default,此回复中还使用的表达式并不是真正等同于参数默认值,而只是一种简单的变通方法,仅当nilfalse均为无效参数值时才起作用。假设布尔参数的默认x值为true,而调用方则传递一个explicit false。然后x or true给出true,即使false已明确传递。更好的版本是if x == nil then x = default end,它也更易读。它仍然不能处理显式nil参数。
Jesper

哦,嘿,这是现在可以接受的答案!真好 (为了记录起见,并在上下文中加上@Undo的评论,jpjacobs的回答在很长一段时间内是公认的答案:我几乎在上面得到了第二个民粹主义徽章。)
Stuart P. Bentley

46

我认为没有别的办法。那只是Lua的心态:没有多余的装饰,除了一些语法糖以外,没有多余的方式来做简单的事情。


10
下面的Stuart P. Bentley的答案完全反对了这个答案,在该答案中,该函数是用表构造函数调用的。这是Lua的优势之一:尽管Lua没有多余的装饰,但是Lua的基本构建块使您可以做无限的事情,这对于语言的小巧和简单而言确实是非凡的。
Colin D Bennett

@ColinDBennett感谢您的发言:OP似乎已阅读您的评论,并于12月相应地更改了接受的答案。(为清楚起见,现在是“ Stuart P. Bentley的回答”:wink :)
Stuart P. Bentley

21

从技术上讲,存在b = b == nil and 7 or b(应该在false有效值为false or 77的情况下使用),但这可能不是您要查找的。


1
如果您不进行检查false,则更简单的方法是将变量放在第一位,默认变量放在最后。b = b or 7
Rebs 2015年

2
由于OP在他们的问题中提到了这一点,所以我认为这是多余的(问题是有关定义除之外的 默认变量的方法b = b or 7)的。
Stuart P. Bentley

6

到目前为止,我发现有意义的唯一方法是执行以下操作:

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()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.