Lua骚操作——三元条件运算符
本文地址:https://www.cnblogs.com/oberon-zjt0806/p/13337577.html
本文参考了这篇文章
三元运算符
(如果您已经了解什么是三元运算符,请大胆第前往下一个章节)
我知道有一元运算符(逻辑非,位反转,负号),二元运算符(加减乘除等),这三元运算符是?
嗯,是的,很多编程语言是支持一种特定的三元运算符(Ternary Operator)的,不过我先不打算用代码的方式来解释这个运算符。我们先以代数的方式来介绍这种运算符。(如果您已经了解什么是三元运算符,请大胆第前往下一个章节)
从代数上来说,我们可以把一个N元运算符(算子)定义为一个N元函数的形式,那么我们假定这个三元运算符叫做\(\Xi_3\),那么实际上,这个三元算子可以被表述为这样一个函数:
\begin{cases}
o_2 &,\mathop{\bf{1}} \left( o_1 \right)=1 \\
o_3 &,\mathop{\bf{1}} \left( o_1 \right)=0 \\
\end{cases}
\]
这里面的\(o_1\)到\(o_3\)就是三个运算元,\(\mathop{\bf{1}} (x)\)叫做逻辑幺函数,这个函数采取任意形式的\(o_1\),若\(o_1\)能被解释为\(F\)(逻辑0,逻辑矛盾式)则该函数都输出\(0\),否则总输出\(1\)。
换言之,上面的三元运算\(\Xi_3\)就表示了这样的含义:
若\(o_1\)不能被解释为逻辑0,则\(\Xi_3\)返回\(o_2\),否则\(\Xi_3\)返回\(o_3\)。
通过这样一种运算符可以进行一个很便利的条件选择,很多程序语言中也都提供了这样的运算符,考虑到我们写程序的代码是线性排版的(排在一行里),因此如果不使用函数而是使用运算符构成中缀表达式挤在运算元中间时,我们会发现:
op1 _ op2 _ op3
是的,与二元运算符不同,使用运算符区分三个运算元时需要至少两个字符,放在两个空挡处,因此很多程序语言提供给的是这个运算符?:,也就是:
op1 ? op2 : op3
用起来非常优雅简洁,可以让我们节省大量的代码行数,少些若干肥肥的if语句,尽管大量嵌套的话可读性会下降,不过尽量避免这一点就好。
Lua中的三元运算符
非常遗憾,翻遍整个Lua的参考文档,Lua并没有提供这个东西……
就在听过这个令人沮丧的消息后,我无意中看到了一个这样的解决方法,可以说骚断了我的腰……
(a and {b} or {c})[1]
这种方案使用了一个and和一个or运算符,号称完成了三元运算符的功能,起初我8太相信,但是看到Lua里关于逻辑运算的描述,我终于看懂了……
为什么会这样
Lua可以说是一个步伐六亲不认,不走寻常路的鬼才语言,虽然目前官网上一片死寂。
其中一个不寻常就是,Lua里只有nil和false可以被解释为逻辑false,其余包括0和[[]](空字符串)在内的所有内容全是true。
而第二个不寻常的玩法就是,Lua的逻辑运算符and和or并不一定返回true或false,它的返回值满足某种吸收原则,这种吸收原则用一句话表示就是:
若表达式针对当前的逻辑运算符可短路求值,则进行左吸收,否则发生右吸收。
分解到这两个运算符身上就是:
- 对于
and运算符,表达式a and b会在a解释为false时返回a(左吸收),否则返回b(右吸收) - 对于
or运算符,表达式a or b会在a解释为true时返回a(左吸收),否则返回b(右吸收)
这样一来我们回到这个情形:
op1 _1 op2 _2 op3
我们当然是希望op1被解释为true时得到op2,否则得到op3。那我们就具体考虑一下当op1被解释为true时应当怎样,要返回op2,则对于前部op1 _1 op2而言需要发生右吸收,对照上面的吸收规则,那么_1就应当是and。依然考虑op1为true,第一次吸收后表达式变成了op2 _2 op3,此时我们希望左吸收,不过这里有个问题,op2被解释为true或false又是两种情况,我们先考虑op2解释为true的情况,此时要完成左吸收,则个根据吸收规则,_2应当使用or运算符,于是整个表达式变成了op1 and op2 or op3,这个表达式可以解决绝大部分情况。
但是,就如前面所担忧的,这种做法并不能处理op1 and false or op3的情况,因为op1 and false部分会被恒定地置为false,而左false对or运算符无法进行左吸收(因为不能短路求值),这种情况下无论op1是多少都只能返回op3。
既然如此,那么我们就需要对op2和op3进行包装,Lua第三个不寻常的地方就是那个妖娆的table,table简直就是个万金油数据结构,什么都能往里塞,而且无论装不装东西,table总能被解释为true,这就不会引发op1 and op2总返回false的情况,从而避免了or的右吸收,于是我们就考虑把op2和op3用两个table分别包装起来。
a and {b} or {c}
然而我们希望返回的结果是表里的元素,而非这张表,因此我们取下元素:
(a and {b} or {c})[1] --Lua里下标从1开始
大功告成!
后记
……
……
我还能说什么呢??太马叉虫了!!!
Lua骚操作——三元条件运算符的更多相关文章
- 论减少代码中return语句的骚操作
一.写作背景 最近组内在推行checkstyle代码规范的检测,关于checkstyle的介绍可以参考:https://checkstyle.sourceforge.io, 在按照checkstyle ...
- Typescript骚操作,在TS里面直接插入HTML
Typescript骚操作,在TS里面直接插入HTML,还有语法提示 先给大家看一个图 因为我不喜欢用很重的框架,主要是并非专业UI,但是偶尔会用到,还是觉得直接element组装受不了,想想能在ts ...
- 闪电侠 Netty 小册里的骚操作
前言 即使这是一本小册,但基于"不提笔不读书"的理念,仍然有必要总结一下.此小册对于那些"硬杠 Netty 源码 却不曾在千万级生产环境上使用实操"的用户非常有 ...
- awk骚操作
一.awk自加 [root@168web3 ~]# head /data/logs/cloud_monitor_rds_cpu.log |awk '{sum+=$NF}END{print sum}' ...
- 如何在命令长度受限的情况下成功get到webshell(函数参数受限突破、mysql的骚操作)
0x01 问题提出 还记得上篇文章记一次拿webshell踩过的坑(如何用PHP编写一个不包含数字和字母的后门),我们讲到了一些PHP的一些如何巧妙地绕过数字和字母受限的技巧,今天我要给大家分享的是如 ...
- UOJ 117 欧拉回路(套圈法+欧拉回路路径输出+骚操作)
题目链接:http://uoj.ac/problem/117 题目大意: 解题思路:先判断度数: 若G为有向图,欧拉回路的点的出度等于入度. 若G为无向图,欧拉回路的点的度数位偶数. 然后判断连通性, ...
- lua和C++交互的lua栈操作——以LuaTinker为例
一. -- C++类注册函数(LuaTinker) 的lua栈操作: -- lua栈内容(执行到pop语句) 栈地址 <--执行语句 space_name[name] = t1 -- (2b8) ...
- 关于map 及 map 骚操作
关于map这个东西 很冷门.................. 但是,这个博客带你稍微了解一下map: map用法:一般当作一个下表无穷大的数组 关于它的骚操作:map的鬼畜用法,可以 ...
- 通过HTTP的HEADER完成各种骚操作
作为一名专业的切图工程师,我从来不care网页的header,最多关心Status Code是不是200.但是HEADER真的很重要啊,客户端从服务器端获取内容,首先就是通过HEADER进行各种沟通! ...
随机推荐
- Bestcoder Round8
4989Summary 既然用C++了就偷懒直接用STL大法了 #include<iostream> #include<algorithm> #include<vecto ...
- Java并发编程的本质是解决这三大问题
[本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究.若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!] 前言 并发编程的 ...
- C#数据结构与算法系列(十):中缀表达式转后缀表达式
1.具体步骤 1)初始化两个栈:运算符栈s1和储存中间结果的栈s2:2)从左至右扫描中缀表达式:3)遇到操作数时,将其压s2:4)遇到运算符时,比较其与s1栈顶运算符的优先级: (1)如果s1 ...
- CODING DevOps 系列第五课:微服务测试——微服务下展开体系化的微服务测试
微服务测试的痛点与挑战 这张图可以形象地展示单体服务和微服务的对比,单体应用就像左边巨大的集装箱,软件模块和应用都包括其中:而微服务就像是由一个小集装箱组成,微小的服务组成一个庞大.完整的系统.单体服 ...
- JAVA SOCKET 通信总结 BIO、NIO、AIO ( NIO 2) 的区别和总结
1 同步 指的是用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪 自己上街买衣服,自己亲自干这件事,别的事干不了.2 异步 异步是指用户进程触发IO操作以后便开始做自己的事情,而当IO操作已 ...
- jvm基础知识—垃圾回收机制
1.首先类的实例化.static.父类构造函数执行顺序 我们来看下面的程序代码: public class A { int a1 = 8; { int a3 = 9; System.out.print ...
- 关于Java的jdbc中 DriverManager.registerDriver(driver); //注册驱动 有没有必要写的思考
加载数据库驱动的时候,有如下部分代码: /1) 注册驱动程序 //给java.sql.Driver接口的引用赋值 com.mysql.jdbc.Driver 实现类对象// Driver driver ...
- linux版本百度网盘只能登录一次的解决方法
rm -rf ~/baidunetdisk 重新启动百度网盘,解决-
- [NLP] REFORMER: THE EFFICIENT TRANSFORMER
1.现状 (1) 模型层数加深 (2) 模型参数量变大 (3) 难以训练 (4) 难以fine-tune 2. 单层参数量和占用内存分析 层 参数设置 参数量与占用内存 1 layer 0.5Bill ...
- idea2020.1.2破解,亲测可行,激活至2089年!
一.下载最新版IDEA2020安装包 官网:https://www.jetbrains.com/idea/download/ 旧版:https://www.jetbrains.com/idea/dow ...