6

而不是在我的函数定义中使用长长的参数列表,我更喜欢传递一些固定参数和一个“附加参数”表,如下所示:

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

上面的代码在所有情况下都可以正常工作,除非我为浮雕传递了“假”:

doit( "Test text", { fontSize = 32, emboss = false } )

当我真的想要 false 时,上面的代码会导致 emboss 被设置为 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)

现在,这当然有效,但它似乎效率低下且过于夸张。我希望有一种更紧凑的方式来做到这一点。

请注意:我发现这个 ruby​​ 结构看起来很有希望,我希望 lua 有类似的东西:

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

2 回答 2

9

Lua 的关系运算符计算为操作数之一的值(即该值不强制为布尔值),因此您可以通过说 来获得与 C 的三元运算符等效的值a and b or c。在您的情况下,a如果不是nil,则要使用,b否则a == nil and b or a

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

不像以前那么漂亮,但你只需要为布尔参数做这件事。


[剪辑 - Lua 代码]

现在,这当然有效,但它似乎效率低下且过于夸张。

请注意:我发现这个 ruby​​ 结构看起来很有希望,我希望 lua 有类似的东西:

[c,b,a].检测 { |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

我希望有一种更紧凑的方式来做到这一点。

这样做的唯一方法是缩短函数名称。;)

于 2012-07-02T21:50:17.517 回答
4

如果您真的想在一行中执行此操作,则需要这样的默认值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
于 2012-07-02T19:17:18.017 回答