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方式不起作用,我只是想知道这是否是唯一的方法。
myfunction{a,b=3,c=2}
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
表中获取(请参阅有关元表的文档)。unpack
(在5.2中移动到table.unpack
),setfenv
(在5.2中已弃用,使用新的_ENV
构造)和select
(从给定的参数列表返回单个值,或使用'#'
返回列表的长度)。在我看来,没有其他的方法。这正是Lua的心态:没有花哨的东西,除了一些语法糖外,没有多余的方式来完成简单的事情。
f(a=1)
将需要检查 arg a
的位置 _每次调用 f
_,这比仅使用定位参数调用 f
要昂贵得多。如果Lua是一种静态语言,在这种语言中,这些信息将是静态的并且在编译时已知,则具有命名参数不会产生运行时成本,并且现在可能已成为一项功能。 - capr从技术上讲,有b = b == nil and 7 or b
(应该在false
是有效值的情况下使用,因为false or 7
的结果为7),但这可能不是您要寻找的。
b = b or 7
- Rebsb = b or 7
以外定义默认变量的方法)。 - Stuart P. Bentleyfunction 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()
一如既往,“Lua 给你力量,你构建机制”。首先要区分的是命名参数和常用的参数列表。
假设你的所有参数都在参数列表中给出,它们都将被初始化。此时,你无法区分“未传递”和“作为nil
传递”之间的区别-两者都将简单地为nil
。设置默认值的选项有:
nil
或false
),可以使用or
运算符。在这种情况下,即使给定的值是false
,也可以进行默认设置。nil
检查param == nil
,可以采用if param == nil then param = default end
或典型的 Lua 三元结构param == nil and default or param
。如果发现自己经常重复使用第2点的模式,可能需要声明一个函数:
function default(value, default_value)
if value == nil then return default_value end
return value
end
(是否使用全局或局部范围来处理此函数是另一个问题,我在这里不会详细讨论。)
我已经包括了以下示例的三种方式:
function f(x, y, z, w)
x = x or 1
y = y == nil and 2 or y
if z == nil then z = 3 end
w = default(w, 4
print(x, y, z, w)
end
f()
f(1)
f(1, 2)
f(1, 2, 3)
f(1, 2, 3, 4)
nil
参数也将被视为缺失。f(nil)
f(nil, 2, 3)
f(nil, 2, nil, 4)
f(1, 2, 3, nil)
Lua的一个较少被人知晓的特性是实际上可以确定传递了多少个参数,包括通过select
函数区分显式传递的nil
参数和"无参数"。让我们使用这个特性来重写我们的函数:
function f(...)
local n_args = select("#", ...) -- number of arguments passed
local x, y, z, w = ...
if n_args < 4 then w = 4 end
if n_args < 3 then z = 3 end
if n_args < 2 then y = 2 end
if n_args < 1 then x = 1 end
print(x, y, z, w)
end
f() -- prints "1 2 3 4"
f(nil) -- prints "nil 2 3 4"
f(1, nil) -- prints "1 nil 3 4"
f(1, nil, 3) -- prints "1 nil 3 4"
f(nil, nil, nil, nil) -- prints 4x nil
Lua提供了一种语法糖,用于以单个表作为唯一参数调用函数:f{...}
等同于f({...})
。此外,{f(...)}
可以用于捕获由f
返回的可变参数(注意:如果f
返回nil
,则表的列表部分会有空洞)。
表还允许将“命名参数”实现为表字段:表允许混合使用列表和哈希部分,因此f{1, named_arg = 2}
在Lua中是完全有效的。
unpack
(在后续版本中为table.unpack
)可用于将表转换为变长参数,可以像参数列表一样对待;但请注意,在Lua中,列表部分不能具有尾部的nil
值,因此无法区分"无值"和nil
。解包/解构到局部变量还有助于性能,因为它消除了重复的表索引。
function f(params)
local x, y, z, w = unpack(params)
-- use same code as if x, y, z, w were regular params
end
f{1, 2, nil}
function f(params)
local x, y, z, w = params.x, params.y, params.z, params.w
-- use same code as if x, y, z, w were regular params
end
f{x = 1, w = 4}
可以混搭:
function f(params)
local x, y, z = unpack(params)
local w = params.w
-- use same code as if x, y, z, w were regular params
end
f{1, 2, w = 4}
__index
元表字段可用于设置一个表,如果 params.name
是 nil
,则使用 name
进行索引,并为 nil
值提供默认值。在传递的表上设置元表的一个主要缺点是,传递的表的元表将会丢失,这可能导致调用方端出现意外行为。你可以使用 getmetatable
和 setmetatable
在操作完 params
后恢复元表,但这样做会比较繁琐,所以我建议不要这样做。
function f(params)
setmetatable(params, {__index = {x = 1, y = 2, z = 3, w = 4}})
-- use params.[xyzw], possibly unpacking / destructuring
end
f{x = 1}
local defaults_metatable = {__index = {x = 1, y = 2, z = 3, w = 4}}
function f(params)
setmetatable(params, defaults_metatable)
-- use params.[xyzw], possibly unpacking / destructuring
end
如果您想要一个没有元表困扰的默认表格,请再次考虑编写一个辅助函数,用于填充具有默认值的表格:
local function complete(params, defaults)
for param, default in pairs(defaults) do
if params[param] == nil then
params[param] = default
end
end
end
这将更改params
表,正确设置默认值;使用方式为params = complete(params, defaults)
。再次提醒,请将defaults
表拖出函数。
z == 3
应该是 z = 3
,但是Stack Overflow不允许我进行一个字符的编辑,而且我对这个主题不是很熟悉,无法以其他有意义的方式做出贡献。 - Hactar如果你的函数不希望参数值传入布尔类型 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]
]]
当默认值为布尔值 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功能。
nil
。这意味着如果我们不向lua函数传递参数,则参数存在但为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
x or default
表达式并不完全等同于参数默认值,而只是一种简单的解决方法,只有在nil
和false
都是无效的参数值时才有效。假设布尔类型参数x
的默认值为true
,调用者传递了一个显式的false
,那么x or true
将返回true
,即使实际上传入了false
。更好的版本应该是if x == nil then x = default end
,这样也更容易理解;但它仍然无法处理显式的nil
参数。 - Jesper