Lua中的三目运算符

0x00 三目运算
熟悉C/C++的老司机都知道三目运算a?b:c,这种写法替换简单的条件判断语句可以在不增加阅读难度的情况下,使代码尽量保持简洁。

    int a, b, ret;
    //if-else
    if (a > b)
        ret = a;
    else
        ret = b;

    //三目运算符
    ret = a > b ? a : b;

0x01 Lua中的三目运算
Lua原生的语义并没有实现三目运算,一般是通过逻辑运算符and和or来模拟三目运算符的。
插播一条广告:
Lua中and和or都使用“短路求值(short_cur evaluation)”,也就是说,它们只会在需要时才去评估第二个操作数。(《Lua程序设计》)

    local a, b, ret;
    ret = a > b and a or b

穷举所有可能性:

  • a > b 时

    a > b and a –> true
    a or b –> a

  • a <= b时

    a > b and a –> false
    a or b –> b

完美!

0x02 Lua中的三目运算符陷阱
按照从特殊到一般的原则:

  • 三目运算的一般形式a ? b : c

    a = true,结果为b
    a = false,结果为c

  • 对应Lua中的a and b or c

    • b = true
      • a = true
        • a and b –> true
        • b or c –> b
      • a = false
        • a and b –> false
        • b or c –> c
    • b = false
      • a = true
        • a and b –> false
        • b or c –> c
      • a = false
        • a and b –> false
        • b or c –> c

可以看到当b = false时,Lua模拟的a and b or c始终返回c并不能还原三目运算符的原貌。
《Lua程序设计》也建议这种情况使用if-else来避免。

0x03 一般化的a and b or c
那么有没有办法可以解决b = false失效的问题呢?
由此我联想到C语言有一道常规的考题:请使用宏定义写一个返回两个值中较小值的方法。
在校时第一次看到本题,第一反应如下:

#define MIN(A,B) A < B ? A : B

然而这种写法在很多嵌套的使用环境中都不能返回正确的结果。比如:2 * MIN(3, 4)展开为 2 * 3 < 4 ? 3 : 4 = 6 < 4 ? 3 : 4,结果为4。
更“工程师”的写法是:

#define MIN(A,B) ((A) < (B) ? (A) : (B))

还有好奇心的同学可以参考:宏定义的正确写法,三目运算的宏定义

从这个示例中,我就在想如何能保证a and b or c中b为真或者b不产生歧义呢?

  • and的运算优先级高于or,简单的改变运算顺序并没有用。
  • 这时就想到了lua中万能的table,能不能把a,b,c都放到table中来改变b的存在呢?要注意{nil}也是一个为true的对象。
    a,b,c都替换为table:{a} and {b} or {c}。
  • 三目运算中a是条件,结果是b或者c。其实a并不需要放入table中,否则{a}就始终为true了,失去了条件的意义。而{b} or
    {c}的结果也必然是一个table,该table只有一个元素。那么通过[1]即可访问。
  • 综上所述,更一般化的Lua三目运算为:(a and {b} or {c})[1]

0x04 总结
诚然,要想知道Lua中三目运算的形式,只需通过搜索就可以找到想要的答案。上述的推理过程多少有点先知道答案,故意往答案上靠的嫌疑。不过我坚信证明一个问题,结论并不是最重要的,重要的是论证的过程。本文仅以我对Lua粗浅的认知来尝试还原一般化的Lua三目运算的推导过程,如有更好的推理过程,可以一起交流。

你可能感兴趣的:(编程语言)