LUA: 寻求高效且无误的默认参数赋值方式

我喜欢在函数定义中传入几个固定的参数和一个“额外参数”的表,而不是使用长长的参数列表,像这样:

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 } )

上面的代码将导致 emboss 被设置为 true ,而我实际上想要 false 。

要明确这一点,我想要的是将第一个非 NIL 值赋给 emboss ,但我得到的是第一个非 false 和 non-NIL 的值。

为了解决这个问题,我写了一小段代码来找到表中第一个非 NIL 值并返回它:

function firstNotNil( ... )
   for i = 1, #arg do
      local theArg = arg[i]
      if(theArg ~= nil) then return theArg end
   end
   return nil
end

使用这个函数,我会将 emboss 赋值重写为:

   local emboss   = firstNotNil(params.emboss, true)

现在,这当然是有效的,但它似乎太低效和繁琐了。我希望有一种更紧凑的方法来实现这一点。

请注意:我发现了这个看起来很有前途的 ruby 构造方法,我希望 lua 有类似的功能:

[c,b,a].detect { |i| i > 0 } --将按顺序分配第一个非零值:c,b,a
点赞
用户1440756
用户1440756

如果你真的想要在一行中完成,你需要像这样设置默认值为 true

local emboss   = params.emboss or (params.emboss == nil)

这并不是非常易读,但是它能起作用。当 params.emboss 没有被设置(当你需要一个默认值时)时,(params.emboss == nil) 的值为 true,否则值为 false。所以当 params.emboss 为 false 时,这个语句为 false,而当它为 true 时,这个语句为 true (true or false = true)。

对于一个默认值为 false 的情况,你最初尝试的也可以工作:

local emboss   = params.emboss or false
2012-07-02 19:17:18
用户501459
用户501459

Lua 的关系运算符返回一个操作数的值(即值不会被强制转换为布尔值),因此可以通过 a and b or c 表达式来获取与 C 中三目运算符等效的结果。在您的情况中,如果 a 不为 nil,则使用 a,否则使用 b,因此表达式为 a == nil and b or a:

local emboss = (params.emboss == nil) and true or params.emboss

虽然不像以前那么漂亮,但您只需要为布尔参数执行此操作。


[snip - Lua code]

现在,这当然起作用,但它似乎非常低效和浪费,因为定义了一个单独的函数来做这件事。

请注意:我发现这个 Ruby 构造,看起来很有前途,我希望 Lua 也有类似的东西:

[c,b,a].detect { |i| i > 0 } -- Assign first non-zero in order: c,b,a

您的 Lua 函数并不比 Ruby 构造更浪费或低效。Ruby 构造在源代码上更加简洁,但语义与 firstNotNil(c,b,a) 并没有什么区别。这两个构造都会创建一个列表对象,将其初始化为一组值,并运行通过线性搜索列表的函数。

在 Lua 中,您可以使用 select 的可变参数表达式跳过创建列表对象:

function firstNotNil(...)
   for i = 1, select('#',...) do
      local theArg = select(i,...)
      if theArg ~= nil then return theArg end
   end
   return nil
end

我希望有更紧凑的方法来实现这个功能。

唯一的方法就是缩短函数名。 ;)

2012-07-02 21:50:17