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进行各种沟通! ...
随机推荐
- VMware历史版本下载【1.0~3.0】
前提:此为走HTTP协议的FTP伺服器,而且有直到Vmware3.0[之后就没了]的版本 link:http://linux.mathematik.tu-darmstadt.de/pub/linux/ ...
- 记一次uboot升级过程的两个坑
背景 之前做过一次uboot的升级,当时留下了一些记录,本文摘录其中比较有意思的两个问题. 启动失败问题 问题简述 uboot代码中用到了一个库,考虑到库本身跟uboot版本没什么关系,就直接把旧的库 ...
- 斐讯N1搭建高性能博客
前些日子我在网上淘到了一台斐讯n1,Amlogic S905D的板子让这个盒子平滑地用上了Armbian系统,有了linux的加持,让这个设备的玩法又上升了一个层次,网上大多都是把他作为旁路由用来富强 ...
- vue 开发环境的搭建
一.整个流程: 安装nodejs>>安装vue>>安装vue-cli>>初始化 webpack(生成代码)>>安装依赖>>运行vue程序 二 ...
- Spring Boot 整合 Apollo
简介 Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限.流程治理等特性,适用于微服务配置管理场景 ...
- java scoket Blocking 阻塞IO socket通信二
在上面一节中,服务端收到客户端的连接之后,都是new一个新的线程来处理客户端发送的请求,每次new 一个线程比较耗费系统资源,如果100万个客户端,我们就要创建100万个线程,相当的 耗费系统的资源, ...
- 在linux裸机部署springBoot项目
一.项目创建及打包 创建项目,打jar包 二.安装JDK 1.在/usr目录下床架java文件夹,将 2.下载jdk8,并上传linux服务器(/usr/java) 下载地址:https://www. ...
- ajax前后端交互原理(4)
4.JSON 4.1 什么是JSON? JavaScript 对象表示法(JavaScript Object Notation)简称JSON,是一种轻量级的数据交换格式.虽然它基于JavaScript ...
- 记一次发布/更新npm包的过程及包版本管理
您可以发布包含package.json文件的任何目录.这里如何首次发布程序包以及如何在以后更新程序包. 如何发布包 制备 了解npm政策 在开始之前,如果您对网站礼仪,命名,许可或其他指南有疑问,最好 ...
- postman不能启动的问题解决
1.postman启动不了,启动时提示“postman resolving transporter buffer”,不能正常启动 第一步,删除:在chrome-更多工具-扩展程序里面删除了postma ...