Lua中如何检查字符串不是nil或空的?

83

我有一些正在使用以下语法的Lua代码:

if (foo == nil or foo == '') then
    foo = "some default value"
end

if语句的目的是测试foo不是空字符串,也不是nil值。

这段代码能否简化为一个if语句而不是两个?


foo = foo or "一些默认值" - doog abides
2
@doog 遵守规则,不会起作用。在 Lua 中 - '' == truenil == false - Kamiccolo
9
foo = (foo or '')=='' and 'default value' or foo 可以翻译为:如果foo为空或未定义,则将其设置为默认值"default value",否则保留原值。 - Egor Skriptunoff
抱歉Kamiccolo,我让一个额外的“.bar”出现了,我已经编辑了问题以删除这个瑕疵。之前的版本在所有地方都使用了“foo.bar”,但我想简化代码示例。 - Uskiver
@EgorSkriptunoff 这回答了问题,但我敢打赌OP的意图是想要更简洁、紧凑但易读/表达的内容,而不是相反的 :) - Oliver
显示剩余3条评论
2个回答

100

你可以做的一件简单的事情是将测试代码封装到一个函数中。

local function isempty(s)
  return s == nil or s == ''
end

if isempty(foo) then
  foo = "default value"
end

如果 s 的长度大于 0,你如何计数?例如:foo 的长度为 2。 - user285594
4
您可以使用 string.len 函数。但是,通过执行 s ~= '' 来检查该字符串长度是否大于零也可以起到同样的效果。 - hugomg
谢谢...虽然问题是关于检查它是否为空 :p - ntg
似乎这个没有检查空格? - Taki7o7

23

这段代码能否通过一个if测试来进行简化,而不是两个if测试?

nil''是不同的值。如果您需要测试s既不是nil也不是'',我认为您应该将它们分别比较,因为这样可以使您的意图最清晰。

以下是一些替代方法及其生成的字节码:

if not foo or foo == '' then end
     GETGLOBAL       0 -1    ; foo
     TEST            0 0 0
     JMP             3       ; to 7
     GETGLOBAL       0 -1    ; foo
     EQ              0 0 -2  ; - ""
     JMP             0       ; to 7

if foo == nil or foo == '' then end
    GETGLOBAL       0 -1    ; foo
    EQ              1 0 -2  ; - nil
    JMP             3       ; to 7
    GETGLOBAL       0 -1    ; foo
    EQ              0 0 -3  ; - ""
    JMP             0       ; to 7

if (foo or '') == '' then end
   GETGLOBAL       0 -1    ; foo
   TEST            0 0 1
   JMP             1       ; to 5
   LOADK           0 -2    ; ""
   EQ              0 0 -2  ; - ""
   JMP             0       ; to 7

在Lua 5.1和5.2中,第二个方法是最快的(至少在我的机器上),但是两种方法之间的差异非常小。为了清晰起见,我会选择第一个方法。


5
foofalse 时,第一个和第三个不会像第二个那样执行相同的操作。 - catwell
使用#foo == 0来检查空字符串,而不是使用foo == '' - 这样做有可能更快吗? - Nas Banov
3
不错的想法。Lua字符串在内部维护它们的长度,因此您不需要计算字符数。但是Lua还会对字符串进行内部缓存,因此检查相等性不需要查看字符;只需检查对象是否相同即可。所以两者应该都很快,但实际上,检索字符串长度的代码路径比从VM堆栈获取两个对象指针来比较它们的代码路径稍微长一些,因此#foo == 0foo ==''慢一点,在5.1版中稍慢,在5.2和5.3版中要慢得多(通过在我的机器上进行基准测试确定)。 - Mud
@NasBanov,#运算符还有一些其他问题。首先,它也适用于表格,例如#{}==0#{[2]='foo'}==0#{a='b'}==0。然后,#42会引发错误;这种行为可能不是期望的...关于速度,#运算符可以被覆盖(在lua 5.2+中)使用一些缓慢的实现,例如:#setmetatable({}, {__len=function()require'socket'.sleep(3)return 7 end});最后,您可能会感到惊讶,但默认的#实现对于表格没有保证的顺序(在某些情况下甚至可能是O(n))。 - fcr
@fcr - 谢谢,这是一个值得思考的观点 - 尽管我认为当我提出这个问题时,我是在暗示知道手头的值是一个字符串,即 #str_foo - Nas Banov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接