在看 skywind3000 大神写的 z.lua 时发现了神秘写法:
os.argv = arg ~= nil and arg or {}
os.path.sep = windows and '\\' or '/'
不需要怎么思考就能知道这个是三目运算。但是在我认知中,Lua 是不支持三目运算符的,定睛一看才发现这个是通过 Lua 布尔运算中的短路特性模拟的三目运算。
Lua 中的短路特性
短路运算的意思是只有在需要的情况下才去检查条件,例如 a and b
当 a = false
时就不需要检查 b
了,或者是 a or b
当 a = true
时也不用检查 b
了。
Lua 中的短路特性与 C 不同点在于,Lua 的布尔操作结果并不只是「真」和「假」。
例如在 C 中:
int a = 4 || 2 // a 的值是 1
而在 Lua 中:
local a = 4 or 2 -- a 的值是 4
local b = 4 and 2 -- a 的值是 2
Lua 将 nil
和 false
当作「假」,其余值都视作「真」(包括 0 )。
然而,Lua 的布尔运算返回的是原值,而不是 true
或 false
。我推测这与 Lua 将 nil
和 false
都当作「假」有关,如果布尔运算返回了 false
,那 nil
的语意就变化了。
nil 是 Lua 特殊的类型,它可能的值只有 nil ,它不在本文讨论范围之中
Lua 三目运算的原理
下面可以通过例子来说明 a and b or c
:
- 当
a = true
时,这时a and b
的值为 a ,由于后续是or
,所以可以直接是 c - 当
a = false
时,这时a and b
的值为 b ,由于后续是or
,所以可以直接是 b,注意这里有个坑等下说
Lua 三目运算的陷阱
在前文中提到,当 a = true
时有坑。当 b 为 false 时,后续是 or
所以最后的值是 c 。这就是 Lua 的三目运算模拟方法失效的场景。
由于 Lua 是一门与 table 结合非常深的语言,我们可以想到利用 table 来解决这一问题,因为 table 在布尔运算中只可能是 nil
和 非nil
(表是否为空),只要创造出一个不为空的表,就可以避免之前的 b = false
的情况出现了。
所以最后的解决办法就是:
(a and {b} or {c})[1]
由于表 {b}
和 {c}
不可能是空表,所以就不会「掉坑」。
最后说一句,Lua 真是太奇妙了!