尾随空参数

lua-users home
wiki


[!] 版本说明: 以下代码适用于旧版本的 Lua,Lua 4。它在 Lua 5 下无法运行。

在纯 Lua 中,传递一个空参数等同于省略该参数。但是,从 Lua 调用的 C 函数可以检测到传递给它们的参数数量(包括空值!)。这会导致很多混淆和丑陋的代码。

在我看来,lua 标准库应该清理掉,不要使用传递的参数数量来确定如何执行。

strfind(s,exp) 应该与 strfind(s,exp,nil,nil) 产生相同的结果。

然后你可以使用最大数量的参数为任何函数编写一个包装器。

function mystrfind(a,b,c,d)
    -- do some extra handling here...
    return strfind(a,b,c,d)
end

示例(ReubenThomas 在 lua-l 列表上的邮件)

如果我运行以下脚本

t = {}
tinsert(t, 3, "hello", 1)
print(t[3])

当我期望 hello 时,我得到 1

[...] 我被这个问题困扰,因为我试图执行以下形式的语句
tinsert(t, n, gsub(...))

并且得到了替换的数量而不是插入的替换结果。这肯定不对吧?

现在我再次阅读它,我意识到这是尾随空值问题的反面 - lua 函数忽略额外的参数,而 c 函数获取所有参数(并且 tinsert 恰好插入其最后一个参数) - 也许最好将此页面命名为“由于 lua 函数和 c 函数对参数的不同处理而产生的问题” - PeterPrade

然而,在该线程的后面,当人们试图修复 tinsert 的奇异之处时,他们遇到了尾随空值问题 - 他们最终不得不意识到你无法用 lua 为 tinsert 编写一个合适的包装函数。让我引用 ET 在该线程中的最后一条消息

[...] 兼容(修复)版本将是

function tinsert(t, ...)
  if arg.n == 1 then
    %tinsert(t, arg[1])
  elseif arg.n == 2 then
    %tinsert(t, arg[1], arg[2])
  else
    error("wronger number of args ("..arg.n+1..") for tinsert");
  end
end
但这仍然会对以下情况产生意外的结果

tinsert(t, foo()) --> 可能生成 tinsert(t,a,b)

或者

tinsert(t, x, foo()) --> 可能生成 tinsert(t, x)

当 foo 没有返回预期的结果数量时。

长期以来,我一直主张让 C 函数在参数处理方面表现得类似于 Lua 函数(将缺失的参数设为空值)。在我看来,tinsert 是一个特别好的例子,说明了可能发生的事情...

Ciao, ET。
另一个例子在 文件输入输出 页面上 - 丑陋的代码,因为 readfrom(nil) 会导致错误(而 readfrom() 是完全合法的)

function readfrom(f)
  local h, err
  if f then h, err = %readfrom(f)
  else      h, err = %readfrom()
  end
  ...

另一个例子出现在邮件列表中

> I just noticed that contrary to what you might expect, if you 
> pass "nil" as the fourth argument of strfind, it does a plain match. 
> Looking at the source, str_find indeed simply looks to see whether it
> has a fourth argument.

Sigh, another example of the arg handling ad hockery...

> This is rather annoying, as in some other cases where it's nice to be
> able to pass "nil" instead of omitting the argument.

You say it...

> It would not be contrary to the 4.0 manual to change this behaviour
>[...]
> Could this be done?

Sure, it _could_.  One could fix this place by converting the test
lua_gettop(L)>3  to  luaL_opt_int(L,3,0)==1,  or one could finally
start thinking about cleaning up argument handling in the C-API...

>[...] is there any way around this?

function strfind(a,b,c,d)
  c = c or 1  -- c has a similar problem...
  if d then
    return %strfind(a,b,c,d)
  else
    return %strfind(a,b,c)
  end
end

在这里添加更多示例...


最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2007 年 7 月 7 日下午 8:23 GMT (差异)