【发布时间】:2011-08-26 17:20:55
【问题描述】:
在 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方式不起作用,我只是想知道这是否是唯一的方法。
【问题讨论】:
在 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方式不起作用,我只是想知道这是否是唯一的方法。
【问题讨论】:
在我看来,没有其他方法。这就是 Lua 的心态:没有多余的装饰,除了一些语法糖,没有多余的方法来做简单的事情。
【讨论】:
从技术上讲,有 b = b == nil and 7 or b(应该在 false 是有效值的情况下使用 false or 7 计算结果为 7),但这可能不是您想要的。
【讨论】:
false,更简单的方法是将变量放在最前面,将默认值放在最后。 b = b or 7
b = b or 7)。
如果您想要命名参数和默认值,如 PHP 或 Python,您可以使用表构造函数调用您的函数:
myfunction{a,b=3,c=2}
(这在 Lua 的很多地方都可以看到,例如 the advanced forms of LuaSocket's protocol modules 和 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 表中获取(请参阅the documentation on metatables)。
当然,使用表构造函数和函数可以实现更高级的参数样式——你可以编写任何你需要的东西。例如,here 是一个构造函数的函数,该函数从定义参数名称和默认值的表中获取命名或位置参数表,以及获取常规参数列表的函数。
作为非语言级别的功能,可以更改此类调用以提供新的行为和语义:
编写参数转换器的一些有用函数是 unpack(在 5.2 中移至 table.unpack)、setfenv(在 5.2 中已弃用,新的 _ENV 构造)和 select(返回单个值来自给定的参数列表,或列表长度为'#')。
【讨论】:
x or default 表达式并不是真正等同于参数默认值,而只是一个简单的解决方法,只有在nil 和false 都为无效的参数值。假设布尔参数x 的默认值是true,调用者传递一个显式false。然后x or true 给出true,即使false 已显式传递。更好的版本是if x == nil then x = default end,它也更具可读性;它仍然无法处理明确的nil 参数。
到目前为止,我发现的唯一有意义的方法是做这样的事情:
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()
【讨论】:
如果您的函数不希望将布尔值 false 和 nil 作为参数值传递,那么您建议的方法很好:
function test1(param)
local default = 10
param = param or default
return param
end
--[[
test1(): [10]
test1(nil): [10]
test1(true): [true]
test1(false): [10]
]]
如果您的函数允许将布尔值false 而非nil 作为参数值传递,您可以按照Stuart P. Bentley 的建议检查是否存在nil,只要默认值即可不是布尔值false:
function test2(param)
local default = 10
param = (param == nil and default) or param
return param
end
--[[
test2(): [10]
test2(nil): [10]
test2(true): [true]
test2(false): [false]
]]
当默认值为 Boolean false 时,上述方法会中断:
function test3(param)
local default = false
param = (param == nil and default) or param
return param
end
--[[
test3(): [nil]
test3(nil): [nil]
test3(true): [true]
test3(false): [false]
]]
有趣的是,颠倒条件检查的顺序确实允许布尔 false 成为默认值,并且名义上性能更高:
function test4(param)
local default = false
param = param or (param == nil and default)
return param
end
--[[
test4(): [false]
test4(nil): [false]
test4(true): [true]
test4(false): [false]
]]
这种方法的工作原理似乎违反直觉,直到进一步检查,发现它们有点聪明。
如果您希望允许允许传递nil 值的函数的默认参数,则需要做一些更丑陋的事情,例如使用可变参数:
function test5(...)
local argN = select('#', ...)
local default = false
local param = default
if argN > 0 then
local args = {...}
param = args[1]
end
return param
end
--[[
test5(): [false]
test5(nil): [nil]
test5(true): [true]
test5(false): [false]
]]
当然,可变参数完全阻止使用它们的函数中的函数参数的自动完成和 linting。
【讨论】:
简短的回答是这是最简单和最好的方法。在 lua 中,变量默认等于 nil 。这意味着如果我们不将参数传递给 lua 函数,则参数是 exits 但为 nil 并且 lua 程序员使用此 lua 属性来设置默认值。
这也不是设置默认值的方法,但您可以使用以下功能
这个函数创建一个错误是你没有将值传递给参数
function myFn(arg1 , arg2)
err = arg1 and arg2
if not err then error("argument") end
-- or
if not arg1 and arg2 then error("msg") end
但这不是一个好方法,最好不要使用这个功能
在图表中显示 [,arg] 中的可选参数
function args(a1 [,a2])
-- some
end
function args ( a1 [,a2[,a3]])
-- some
end
【讨论】: