Lua使用方式介绍

背景

Lua是C语言开发的脚本语言,设计的目的是为了嵌入到程序中,因此被设计得轻量小巧。Nginx配置中可以直接嵌入Lua 代码或引入Lua 文件,Redis支持运行Lua语句和脚本,Wireshark中使用Lua脚本自定义协议。
本文用于收集常用的语法和API,用作记事本而不会过多深入,内容后续会不断更新。

1.Lua数据类型和变量

Lua有8种基本类型:
[1] boolean布尔: true和false;在Lua中,仅false和nil表示假;其他为真,这与部分语言中默认值为假不同;
[2] number数值: 整数和浮点数;
[3] string字符串:由单引号或者双引号包含的部分;
[4] function函数: 由C语言或者LUA定义的函数;
[5] table表:灵活的数据结构,可以用作数组、哈希表、集合等多种数据类型;
[6] nil: 空对象、空值、或者未声明变量的值;
[7] userdata: C语言数据结构,lua不能直接访问和操作这些数据,只能通过C语言的API来操作;
[8] thread类型: 在Lua中表示一个协程,用于实现并发。
lua作为动态语言,声明变量时无需指定变量的类型,赋值决定类型,之后可通过type()函数查看变量的类型.

var1 = true
var2 = 100
var3 = 100.01
var4 = "test"
var5 = function(a)print(a)
endvar6 = {}
var7 = nilprint("type var1 is:" .. type(var1))
print("type var2 is:" .. type(var2))
print("type var3 is:" .. type(var3))
print("type var4 is:" .. type(var4))
print("type var5 is:" .. type(var5))
print("type var6 is:" .. type(var6))
print("type var7 is:" .. type(var7))

运行结果如下:

type var1 is:booleantype var2 is:numbertype var3 is:numbertype var4 is:stringtype var5 is:functiontype var6 is:tabletype var7 is:nil

变量有全局变量和局部变量之分,全局变量全局有效,而局部变量(在声明时添加local)仅在所在语句块内有效:

-- a为全局变量
>a=0-- b为局部变量
>local b='ss'

变量之间的比较,使用 == 表示相等, ~=表示不等:

>local a=1>print(a==1)
true>print(a~=1)
false

数值方面的大小比较以及基本运算与Java相同。

2.逻辑运算与条件判断

使用 and or not 表示与或非:

>local b="ss">print(b=="s" or b=="ss")
true

Lua的if语法为:

if 条件 then逻辑
endif 条件 then逻辑1
else 逻辑2
endif 条件1 then逻辑1
elseif 条件2 then逻辑2
else逻辑3
end

3.字符串

Lua中定义字符串时,可用单引号或者双引号。

local str = "hello world"

[1] 长度

-- string.len(arg)返回字符串长度
>local str = "hello world"
>print(string.len(str))
11

[2] 拼接

--使用..进行字符串拼接
>local str = "hello world"
>str_print = "str is : " .. str .. "."
>print(str_print)str is : hello world.

[3] 大小写转换

--全部转为大写string.upper(arg):
--全部转为小写string.lower(arg):>local str = "hello"
>strUpper = string.upper(str)
>print("strUpper: " .. strUpper)
strUpper: HELLO>strLower = string.lower(strUpper)
>print("strLower: " .. strLower)
strUpper: HELLO

[4] 是否包含

--  string.find(str, "test") 返回"test"在str中的其实索引,如果不存在,返回nil
>str = "test1"
>find_result = string.find(str, "test")
>print(find_result)
1--可通过是否等于nil来判断是否包含
str = "test1"
if string.find(str, "test") ~= nil thenprint("yes")
elseprint("no")
end

[5] 截取

-- string.sub(str, i [, j]) 将str从i截取到j位,如果省略j表示截取到字符串尾部
>local str = "hello world"
>local str_sub1=string.sub(str, 1)
>print("str_sub1 is " .. str_sub1)
str_sub1 is hello world>local str_sub15=string.sub(str,1,5)
>print("str_sub15 is " .. str_sub15)
str_sub15 is hello

使用string.sub(str, i [, j]方法时注意Lua中位置索引从1开始而不是0开始,j是未知索引而不是长度,i和j都为闭区间。
[6] 删除空格

function trim(inputString)return string.gsub(inputString, "^%s*(.-)%s*$", "%1")
end-- 示例用法:
local myString = "   Hello, World!   "
local trimmedString = trim(myString)  -- 返回 "Hello, World!"
print(trimmedString)  -- 输出: Hello, World!

[7] 替换

--string.gsub(str, "test", "hello")
-- 将str字符串中的test改成hello
>local str = "test1test2test"
>local result = string.gsub(str, "test", "hello")
>print(result)
hello1hello2hello

4.table类型

table可以被当做数组或者哈希表使用。
数组:

-- 1.声明方式:使用大括号
local myArray = {"a", "b", "c"}--2.获取长度:通过#数组名,获取数组长度
>print(#myArray)
3--3.添加元素
--通过table.insert(myArray, e) 添加元素
>local emptyTable = {}
>table.insert(emptyTable,"x")
>table.insert(emptyTable,"y")
>print(#emptyTable)
2
--也可以直接通过下标获取、设置、添加元素
>emptyTable[1]="x1"
>print(emptyTable[1])
x1--4.删除元素
table.remove(myArray) -- 删除myArray数组最后一个元素
table.remove(myArray, i) --删除myArray数组的第i个元素--5.遍历
local myArray = {"a", "b", "c"}
for k, v in pairs(myArray) doprint(v) -- v为数组元素 a b c
end

其中local emptyTable = {}声明了一个数组,执行table.insert(emptyTable,"x")向数组中添加了一个元素"x", 等价于emptyTable[1] ="x".

其他语言中,一般下标是下标,不会认为是整数类型的Key; 在Lua语言中,可以认为emptyTable[1] ="x"是向哈希表emptyTable中添加了一个键值对,键是1,值是x.

哈希表:

--1.声明哈希表,使用{}
local myHash = {name = "sy", role = "role_a"}--2.添加元素
myHash.age=18--3.删除元素
myHash.age = nil--4.遍历
local myHash = {name = "sy", role = "role_a"}
for k, v in pairs(myHash) doprint(k,v) -- k为键,v为值
end

注意:当哈希表中的键的值被设置为nil时,Lua在下一次垃圾回收时会清理这个键值对。

5.循环逻辑

while循环

while condition do-- 这里是循环体,只要condition为真,就会不断执行这里的代码
end--案例如下:
local i = 1
while i <= 5 doprint(i)i = i + 1
end

for循环
前面介绍table时已经用过for循环,除了遍历数组和哈希表外,还可以指定循环次数:

-- initial 是起始值,limit 是结束值,step 是步长(步长可以是正数也可以是负数,默认为 1)
for var = initial, limit, step do-- 这里是循环体
end--案例如下:
local myArray = {"a", "b", "c"}
for i = 1, #myArray doprint(myArray[i])
end

注意:Lua有goto,但是没有continue和break.

6.函数

和变量相同,Lua定义函数时可以通过local指定作用域: 全局或者局部。
使用关键字function声明函数,模板如下所示:

function myFunName()--函数逻辑
end

(1) 函数入参
可以在声明时添加参数

function myFunName(arg1,arg2,agr3)--函数逻辑
end--案例如下:
function printArgsFunc(arg1, arg2, arg3)print("args is: " .. arg1 .. arg2 .. arg3)
end
>printArgsFunc('a','b','c')
args is: abc

(2) 返回值
当函数需要返回数据时,通过添加return语句返回;和python相似,返回多个数据时,使用逗号分隔。

function myFunName(arg1,arg2,agr3)--函数逻辑return arg1,arg2,agr3
end--案例如下:
function getArgsFunc(arg1, arg2, arg3)return arg1, arg2, arg3
end
>local result1, result2, result3, result4 =  getArgsFunc("a","b","c")
>print("result1 is: " .. result1)
>print("result2 is: " .. result2)
>print("result3 is: " .. result3)
>print(result4)result1 is: a
result2 is: b
result3 is: c
nil

由于Lua是脚本语言,因此需要先定义再调用,调用方式与python类似。

7.对象

Lua本身不具备面向对象的语法,但是可以使用面向对象的思想通过表数据结构模拟出对象。在介绍对象前,有必要提前说明一下元表的概念和一个Lua语法糖。

7.1 元表

元表的概念是定义原始值在特定下的行为。概念比较抽象和难懂,理解元表需要结合使用案例进行。
关联方式
元表是一种特殊的表,每个表可以关联一个元表,通过setmetatable(表,元表)方法关联:

t = {}
mt = {}
-- 表t关联mt元表
setmetatable(t,mt)

__index属性
当从表t中查询不存在的key时,转向元表mt的__index属性。有两种情况:
[1] __index为表:直接从__index表中根据key取值

>t = {}
>mt = { __index={ a=1, b=2 }}
>setmetatable(t,mt)
>print(t.a)
1
>print(t.c)
nil

分析: mt为t的元表,访问t.a和t.c时,因为t表中不存在a和c属性,请求会转向元表的__index属性,
此时__index属性是元表且其中有a属性—返回1,没有c属性—返回nil.

[2] __index为函数:将表t和key作为参数传递给__index函数

>t = {}
>mt = { __index=function(t, key)return "sy"end	
}
>setmetatable(t,mt)
>print(t.a)
sy
>print(t.c)
sy

分析: mt为t的元表,访问t.a和t.c时,因为t表中不存在a和c属性,请求会转向元表的__index属性,
此时__index为方法,将t和key传递给__index方法,该方法返回固定值“sy”, 因此t.a和t.c得到的结果均为"sy".

__newindex属性
当向表t中添加新的key时,转向元表mt的__newindex属性。有两种情况:
[1] __newindex为表:直接添加到__newindex表中根据key取值

>t = {}
>mt = { __newindex={}
}
>setmetatable(t,mt)
>t.a="aa"
>print(t.a)
nil
>print(mt.__newindex.a)
aa

分析:mt为t的元表,向t中添加元素时,转向元表mt的__newindex属性,此时该属性为表,将元素添加到__newindex中。

[2] __newindex为函数:将表t和key作为参数传递给__newindex函数

>t = {}
>mt = { __newindex=function(t,k,v)rawset(t,k,v)end
}
>setmetatable(t, mt)
>t.a="aa"
>print(t.a)
aa

分析:mt为t的元表,向t中添加元素时,转向元表mt的__newindex属性,此时该属性为函数,将t,k,v作为参数传递给__newindex函数;其中rawset(t,k,v)函数将 k,v设置到t表中。

其他属性:
__add用于重载表的操作符(+),类似的还有减法、乘除法等。

7.2 语法糖

Lua调用表中的方法时,如果需要将自己作为参数传递,可以使用冒号调用方法,从而省略第一个参数,如下所示:

table.func(table,arg1,argn)
-- 等价于
table:func(arg1,argn)

以下通过一个案例进行说明。

t = {name="sy",getName = function(t)return t.nameend
}
print(t.getName(t))

上述代码定义了一个表t, 内部定义了一个name属性和一个getName方法:getName方法接受一个表参数,并返回这个表的name属性,此时获取t的name属性需要传参t。
上面的方法可以修改一下,将t用self修改一下:

t = {name="sy",getName = function(self)return self.nameend
}
print(t.getName(t))
-- 等价于print(t:getName())

如此,使用getName方法的人,不会为getName传递其他表参数,认为这是特定为t表定制的方法。
print(t.getName(t))可以使用语法糖print(t:getName())代替。t:getName()给人一种调用t对象的getName方法的感觉。

7.3 对象

定义一个Person表,只有一个name属性和一个getName方法:

>Person={ name = "sy",getName = function(self)return self.name;end
}>print(Person:getName())
sy

为Person添加一个new方法:

function Person:new()local t = {}setmetatable(t,{__index=self})return t
end

通过Person的new方法可以创建一个新Person表,此时存在3个表:Person表,匿名表,t表(新Person表):
new方法中声明了一个t表并在函数调用结束时返回t表,即调用new方法最终得到的新Person表是t表;
{__index=self}定义了一个匿名表;通过setmetatable方法将匿名表设置为t表的元表;
而匿名表的__index属性为self,即Person表;
此时,当获取 t表中不存在的属性或者方法时,会转向元表的__index属性,即Person表。
因此,可通过新Person表访问Person表的属性和方法:

>local p = Person:new()
>print(p:getName())
sy

进一步地,可以为new方法添加一个元表参数,该元表将继承Person表的属性:

function Person:new(tableArg)local t = tableArg or {}setmetatable(t,{__index=self})return t
end

此时, 通过new方法得到的元表不仅拥有Person表的属性,还保留tableArg表自身的属性:

local Student = { class = 4 }
>local stuInstance = Person:new(Student)
>print(stuInstance.class)
4
>print(stuInstance:getName())
sy

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/20939.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JMeter源码解析之SplashScreen.java

JMeter源码解析之SplashScreen.java完结 SplashScreen.java主要作用 JMeter GUI启动加载界面。 文件路径 路径地址&#xff1a;…\apache-jmeter-5.1\src\core\org\apache\jmeter\SplashScreen.java 关于SplashScreen内容中的代码解析 package org.apache.jmeter;import …

队列——一种操作受限的线性表

队列 队列&#xff08;Queue&#xff09;简称队&#xff0c;也是一种操作受限的线性表&#xff0c;只允许在表的一端进行插入&#xff0c;而在表的另一端进行删除。向队列中插入元素称为入队或进队&#xff0c;删除元素称为出队或离队。队列中的元素是先进先出&#xff08;Fir…

大聪明教你学Java | 深入浅出聊 Stream.parallel()

前言 &#x1f34a;作者简介&#xff1a; 不肯过江东丶&#xff0c;一个来自二线城市的程序员&#xff0c;致力于用“猥琐”办法解决繁琐问题&#xff0c;让复杂的问题变得通俗易懂。 &#x1f34a;支持作者&#xff1a; 点赞&#x1f44d;、关注&#x1f496;、留言&#x1f4…

MySQL学习——选项文件的使用

MySQL 的许多程序都可以从选项文件&#xff08;有时也被称为配置文件&#xff09;中读取启动选项。选项文件提供了一种方便的方式来指定常用的选项&#xff0c;这样你就不必每次运行程序时都在命令行上输入这些选项。 要确定一个程序是否读取选项文件&#xff0c;你可以使用 -…

man命令的作用

man命令是Linux操作系统中一个非常实用的命令&#xff0c;它用于查看命令的手册页面&#xff0c;帮助用户了解特定命令的用法、选项和参数。这不仅对新用户在学习如何使用新命令时很有帮助&#xff0c;也方便了经验丰富的用户快速查找命令的详细信息。以下是具体介绍&#xff1…

[论文精读]Supervised Community Detection with Line Graph Neural Networks

论文网址:[1705.08415] Supervised Community Detection with Line Graph Neural Networks (arxiv.org) 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 ⭐内涵大量可视…

高速模拟信号链的设计学习

目录 概述&#xff1a; 定义&#xff1a; 断开&#xff1a; 链路设计&#xff1a; 结论&#xff1a; 概述&#xff1a; 由于对共模参数及其与设备之间的关联缺乏了解&#xff0c;客户仍然会提出许多技术支持问题。ADC数据表指定了模拟输入的共模电压要求。关于这方面没有太…

jenkins应用2

1.jenkins应用 1.jenkins构建的流程 1.使用git参数化构建&#xff0c;用标签区分版本 2.git 拉取gitlab远程仓库代码 3.maven打包项目 4.sonarqube经行代码质量检测 5.自定义制作镜像发送到远程仓库harbor 6.在远程服务器上拉取代码启动容器 这个是构建的整个过程和步骤…

C# 反射类Assembly 程序集(Assembly)用法

常见的两种程序集&#xff1a; 可执行文件&#xff08;.exe文件&#xff09;和 类库文件&#xff08;.dll文件&#xff09;。 在VS开发环境中&#xff0c;一个解决方案可以包含多个项目&#xff0c;而每个项目就是一个程序集。 他们之间是一种从属关系&#xff0c;也就是说&…

java —— 匿名内部类与 Lambda 表达式

一、匿名内部类 匿名内部类是一种没有名称的类&#xff0c;多用于只使用一次的情况&#xff0c;本质上就是其所继承的父类或接口的一个子类。 &#xff08;一&#xff09;继承普通类的情况 public class Test{public void method(){System.out.println("通用方法"…

Python与Android连接:深入探索与实现

Python与Android连接&#xff1a;深入探索与实现 在现代移动应用开发领域&#xff0c;Python和Android的结合使用为开发者带来了无限的可能性。这种跨平台的组合不仅拓宽了开发者的视野&#xff0c;也极大地提升了应用的灵活性和可扩展性。本文将从四个方面、五个方面、六个方…

【NLP开发】Python实现聊天机器人(微信机器人)

&#x1f37a;NLP开发系列相关文章编写如下&#x1f37a;&#xff1a;1&#x1f388;【小沐学NLP】Python实现词云图&#x1f388;2&#x1f388;【小沐学NLP】Python实现图片文字识别&#x1f388;3&#x1f388;【小沐学NLP】Python实现中文、英文分词&#x1f388;4&#x1…

转让北京电力施工总承包二级资质变更条件和流程

在电力工程领域&#xff0c;资质等级是企业能否参与竞标、承接工程的重要标志之一。北京电力工程总包二级资质的转让&#xff0c;是指已经取得该资质的企业将其资质转让给需要的企业。这种转让是基于合作与共赢的原则&#xff0c;旨在推动电力工程行业健康、稳定发展&#xff0…

记录使用自定义编辑器做试题识别功能

习惯了将解析写在代码注释&#xff0c;这里就直接上代码啦&#xff0c;里面用到的bxm-ui3组件库是博主基于element-Plus做的&#xff0c;可以通过npm i bxm-ui3自行安装使用 // 识别方法&#xff1a; // dom 当前识别数据所在区域, questionType 当前点击编辑选择的题目类型&a…

力扣刷题--LCR 135. 报数【简单】

题目描述 实现一个十进制数字报数程序&#xff0c;请按照数字从小到大的顺序返回一个整数数列&#xff0c;该数列从数字 1 开始&#xff0c;到最大的正整数 cnt 位数字结束。 示例 1: 输入&#xff1a;cnt 2 输出&#xff1a;[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,1…

codeblock怎么编程:从入门到精通的全面指南

codeblock怎么编程&#xff1a;从入门到精通的全面指南 在数字化时代&#xff0c;编程已成为一项不可或缺的技能。Code::Blocks作为一款流行的开源集成开发环境&#xff08;IDE&#xff09;&#xff0c;为初学者和有经验的开发者提供了强大的编程支持。那么&#xff0c;codebl…

C是结构化编程语言吗:深度剖析与多维度解读

C是结构化编程语言吗&#xff1a;深度剖析与多维度解读 在编程语言的浩瀚海洋中&#xff0c;C语言以其独特的魅力占据着重要的地位。那么&#xff0c;C语言是否可以被归类为结构化编程语言呢&#xff1f;这是一个值得深入探讨的问题。本文将从四个方面、五个方面、六个方面和七…

Qt | Qt 资源简介(rcc、qmake)

1、资源系统是一种独立于平台的机制,用于在应用程序的可执行文件中存储二进制文件(前面所讨论的数据都存储在外部设备中)。若应用程序始终需要一组特定的文件(比如图标),则非常有用。 2、资源系统基于 qmake,rcc(Qt 的资源编译器,用于把资源转换为 C++代码)和 QFile …

java—MyBatis框架

简介 什么是 MyBatis&#xff1f; MyBatis 是一款优秀的持久层框架&#xff0c;它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO&…

软件公司为什么必须要使用低代码系统?

在当今软件行业全国比较内卷的大环境下&#xff0c;软件公司面临着前所未有的挑战。为了在这个竞争激烈的市场中生存并脱颖而出&#xff0c;驰骋低代码设计者认为&#xff0c;软件公司必须要使用低代码系统。以下是几个关键的原因&#xff1a; 时代发展的必然选择 低代码系统是…