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进行各种沟通! ...
随机推荐
- mongoDB的基本使用方法
MongoDB 安装(乌班图系统) apt install mongodb mongoDB与sql的对比 SQL术语/概念 MongoDB术语/概念 解释/说明 database database 数 ...
- ES6 基本语法:
ES6.基本语法* ES6可以使用=>作为函数表达形式,简单的风格: 参数 + => +函数体;* 在JS中是以var定义一个变量 ,在ES6中是以let定义变量; let 和 var 区 ...
- MongoDB设计方法及技巧
MongoDB是一种流行的数据库,可以在不受任何表格schema模式的约束下工作.数据以类似JSON的格式存储,并且可以包含不同类型的数据结构.例如,在同一集合collection 中,我们可以拥有以 ...
- 面试题64:求 1 + 2 + ... + n
这道题目条件限制严格,需要发散思维...但是作者是以 C++ 语言特性来做讲解的,对于 Java 狗只能说稍微有点参考意义吧!
- 高性能IO —— Reactor(反应器)模式
讲到高性能IO绕不开Reactor模式,它是大多数IO相关组件如Netty.Redis在使用的IO模式, 为什么需要这种模式,它是如何设计来解决高性能并发的呢? 最最原始的网络编程思路就是服务器用一个 ...
- 下订单更新订单表然后减少库存表中的数据,出现库存超卖,使用数据库和redis坚决库存超卖的问题
上面的代码更新库存的数据,存在多线程的问题,第一种方法使用synchronized关键字修饰的语句块代码,但是性能较低,并且还是存在问题的 在分布式的场景下,当前库存系统部署在多个tomcat上,即使 ...
- 吉比特&雷霆游戏--2020春招实习
笔试 题量较大,仅记了一些印象比较深刻的题. 题型为选择 + 填空(给C++代码填输出结果) + 编程 编程题不会太难,最难的就一道字符串的全排列(类似剑指offer第38题LeetCode链接)可以 ...
- node+ajax实战案例(4)
4.用户登录实现 4.1.用户登录实现思路 1 用户输入登录信息,点击登录的时候把用户登录的这些信息收集起来,然后组装数据通过ajax方式发送到后台 2 后台接到用户输入的登录信息,把这些信息拿去和数 ...
- Nuxt+Express后端api接口配置与实现方式
Nuxt.js 是一个基于 Vue.js 的轻量级应用框架,可用来创建服务端渲染 (SSR) 应用.本文带你了解在 Nuxt.js 中使用 Express 如何编写实现后端的 api 接口. 创建接口 ...
- 恕我直言你可能真的不会java第11篇-Stream API终端操作
一.Java Stream管道数据处理操作 在本号之前写过的文章中,曾经给大家介绍过 Java Stream管道流是用于简化集合类元素处理的java API.在使用的过程中分为三个阶段.在开始本文之前 ...