与其在我的函数定义中使用长参数列表,我更喜欢传递一些固定参数和一个"附加参数"表,如下所示:
function:doit( text, params )
end
这很好,因为它允许我稍后添加新的命名参数,而不会破坏旧调用。
当我尝试为某些参数强制使用默认值时,会出现我遇到的问题:
function:doit( text, params )
local font = params.font or native.systemBold
local fontSize = params.fontSize or 24
local emboss = params.emboss or true
-- ...
end
上面的代码在所有情况下都可以正常工作,除了我为浮雕传递了"false":
doit( "Test text", { fontSize = 32, emboss = false } )
上面的代码将导致浮雕在我真正想要 false 时设置为 true。
需要明确的是,我想要的是将第一个非 NIL 值分配给浮雕,相反,我得到了第一个非虚假和非 NIL。
为了解决这个问题,我写了一小段代码来查找表中的第一个非 NIL 值并返回该值:
function firstNotNil( ... )
for i = 1, #arg do
local theArg = arg[i]
if(theArg ~= nil) then return theArg end
end
return nil
end
使用这个函数,我将重写浮雕分配,如下所示:
local emboss = firstNotNil(params.emboss, true)
现在,这当然有效,但它似乎效率低下且过分。 我希望有一种更紧凑的方法可以做到这一点。
请注意:我发现这个红宝石结构看起来很有前途,我希望lua有类似的东西:
[c,b,a].detect { |i| i > 0 } -- Assign first non-zero in order: c,b,a
Lua的关系运算符计算为其中一个操作数的值(即该值不强制为布尔值),因此您可以通过说a and b or c
来获得C的三元运算符的等价物。在您的情况下,如果它不是nil
,您想使用 a
,否则b
,因此a == nil and b or a
:
local emboss = (params.emboss == nil) and true or params.emboss
不像以前那么漂亮了,但你只需要为布尔参数做这件事。
[截图 - Lua 代码]
现在,这当然有效,但它似乎效率低下且过分。
请注意:我发现这个红宝石结构看起来很有前途,我希望 lua 有 类似的东西:
[c,b,a].detect { |i| i> 0 } -- 按顺序分配第一个非零:c,b,a
您的Lua函数不再过于夸张或效率低下。就源文本而言,Ruby 结构更简洁,但语义与 firstNotNil(c,b,a)
并没有真正的区别。这两个构造最终都会创建一个列表对象,使用一组值对其进行初始化,并通过线性搜索列表的函数运行该对象。
在 Lua 中,您可以通过将 vararg 表达式与 select
一起使用来跳过列表对象的创建:
function firstNotNil(...)
for i = 1, select('#',...) do
local theArg = select(i,...)
if theArg ~= nil then return theArg end
end
return nil
end
我希望有一种更紧凑的方法可以做到这一点。
关于唯一的方法是缩短函数名称。 ;)
如果你真的想在一行中做到这一点,你需要这样的东西来获得默认值 true:
local emboss = params.emboss or (params.emboss == nil)
它的可读性不是很好,但它有效。(params.emboss == nil) 在未设置 params.emboss 时计算结果为 true(当您需要默认值时),否则为 false。因此,当 params.emboss 为假时,该语句为假,当为真时,该语句为真(真或假 = 真)。
对于默认值 false,您最初尝试的方法将起作用:
local emboss = params.emboss or false