Lua基本数据类型

一、Lua是什么?

1.1 Lua的历史

Lua是由Roberto Ierusalimschy、Luiz Henrique de Figueiredo和Waldemar Celes于1993年创建的,当时他们是巴西里约热内卢天主教大学计算机图形技术组(Tecgraf)的成员。在开发Lua之前,他们曾参与过数据描述/配置语言"SOL"(简单对象语言)和"DEL"(数据录入语言)的工作。这两种语言是他们独立开发的两个不同项目的一部分,旨在增强工程应用的交互式图形程序。然而,SOL和DEL缺乏许多控制流结构,因此需要增加完整的编程能力。因此,为了满足这个需求,他们创建了Lua。

在《The Evolution of Lua》中,Lua的作者写道,在1993年,Tcl是Lua的唯一真正竞争者,但Tcl的语法相对较为陌生,且只能在Unix平台上运行,不太适合数据描述。此外,LISP和Scheme的语法也不够友好,Python还处于起步阶段。在Tecgraf的自由、自主的氛围下,他们自然而然地尝试开发自己的脚本语言。考虑到这门语言的潜在用户不一定是专业程序员,因此他们希望语言避免复杂的语法和语义。另外,由于Tecgraf的客户使用各种不同的计算机平台,他们希望新语言的实现能够高度可移植。最后,考虑到Tecgraf的其他产品也需要嵌入脚本语言,他们决定让新语言像SOL一样提供带有C API的库。

1.2 Lua的特点

Lua 作为一种脚本语言具有多种特点,以下是其中一些主要的特点:

  • 轻量级和可嵌入性:Lua 的核心非常小巧,可以轻松地嵌入到其他应用程序中,作为脚本语言使用。这使得 Lua
    在游戏开发、嵌入式系统和其他领域中得到广泛应用。
  • 简洁清晰的语法:Lua 的语法简洁明了,易于学习和使用。它没有过多的冗余符号,采用基于表达式的语法,没有大括号,使用 end
    关键字来结束块,使得代码更加清晰易读。
  • 动态类型和自动内存管理:Lua 是一种动态类型语言(运行时进行变量类型检查和解析),变量不需要显式声明类型。它还具有自动内存管理,通过垃圾回收机制来管理内存,简化了开发者的工作。
  • 强大的数据描述能力:Lua 支持多种基本数据类型,包括数字、字符串、布尔值、表(类似于字典或关联数组)、函数等。表是 Lua
    中最重要的数据结构之一,可以灵活地表示复杂的数据集合。
  • 灵活的扩展能力:Lua 提供了丰富的扩展接口,可以通过 C/C++ 编写扩展模块,并与 Lua 脚本进行交互。这种可扩展性使得 Lua
    可以与其他语言轻松集成,满足不同应用场景的需求。
  • 高性能:Lua 的解释器经过优化,执行速度较快,适合用于处理大规模的数据和复杂的逻辑。
  • 动态代码执行:Lua 支持动态代码执行,可以通过 load 和 loadfile 函数动态加载并执行 Lua 脚本,灵活性很高。
  • 适用于嵌入式系统:由于 Lua 的轻量级和可嵌入性,它在嵌入式系统中得到广泛应用,可以用于控制设备、配置参数等任务。

二、Lua语法

2.1 输出print、单行注释、多行注释

lua 复制代码
print("hello world")
--单行注释
 
--[[
多行注释
多行注释
]]

2.2 变量

  • lua中四种简单的变量类型:nil、string、boolean、number。除此之外还有:function、table、userdata、thread。
  • 不需要声明变量类型;可通过type函数获取变量类型,type函数返回值是string。
  • 变量可随便赋值。Lua 中的变量是动态类型的,这意味着变量没有预定义的类型,类型会在运行时根据赋给变量的值来决定。
  • lua中没有赋值过的变量,默认类型是nil。

2.3 字符串

  1. 在 Lua 中,字符串可以用双引号"、单引号'或者长括号[[ ]]来表示。
lua 复制代码
a="hello"
print(a)
b=[[hello]]
print(b)
  1. 使用#运算符可以获取字符串长度。
lua 复制代码
a="hello world"
print(#a)

3.可以使用...运算符来拼接字符串。也可以使用string.format来进行拼接。

lua 复制代码
a="一"    
print("一个汉字长度:"..#a)  --一个汉字长度是3
print(string.format("今年 %s 岁",'18'))

4.多行打印

在Lua中,可以使用多行字符串来打印多行文本。多行字符串可以通过在字符串的开始和结束使用双方括号[[和]]来创建。也可以通过行末尾添加"\n"来进行多行打印。

lua 复制代码
a=[[1.hello
2.world]]
print(a)

5.类型转换

在Lua中,可以使用 tostring 函数将一个值转换为字符串。这个函数可以接受任何基本类型的值作为参数,并返回该值的字符串表示形式。

lua 复制代码
a=false
print(tostring(a))

6.字符串操作(大小写、反转、查找、截取、重复)

字符串相关操作,不会改变原字符串。Lua中索引从1开始。

lua 复制代码
str="YsL"
str1=string.upper(str)
print("原字符串:"..str..",全部大写为:"..str1)
str1=string.lower(str)
print("原字符串:"..str..",全部小写为:"..str1)
str1=string.reverse(str)
print("原字符串:"..str..",反转字符串为:"..str1)
 
--原字符串:YsL,全部大写为:YSL
--原字符串:YsL,全部小写为:ysl
--原字符串:YsL,反转字符串为:LsY

str="YsL"
print("---------字符串查找")
print(string.find(str,"sL")) --2  3
 
print("---------字符串截取")
print(string.sub(str,2))     --sL
print(string.sub(str,2,2))   --s
 
print("---------字符串重复:"..string.rep(str,3)) --字符串重复:YsLYsLYsL

print("---------字符串修改")
print(string.gsub("Session",'s','*'))    
 
--Se**ion	2
--string.gsub()返回两个结果,第二个值表示修改了几个字符。

7.字符串与ASCII互转

lua 复制代码
a=string.byte("Lua",1)
print(a) --76
 
a=string.char(a)
print(a) --L

2.4 function

在Lua中,函数是一种可以封装代码以便重复使用的基本结构。函数可以接受参数,并且可以返回一个或多个值。Lua不支持重载,但重载后并不报错,默认调用最后声明的函数。

1.无参无返回值

lua 复制代码
--先声明
function fun1()
	print("my fun1")
end
 
--再调用
fun1()

2.有参无返回值

lua 复制代码
function fun3(a)
	print(a)
end
 
fun3(1)
fun3("hello world")
fun3(true)
fun3(nil) --nil
fun3()    --nil
fun3(1,2) --1     实参和形参个数不匹配,会补空或丢弃

3.有一个返回值

lua 复制代码
function fun4(a)   --直接return即可
	return a
end
 
temp=fun4(1)
print(temp)

4.有多个返回值

lua 复制代码
function fun5(a)   --支持返回多个值
	return a,-1
end
 
temp1,temp2,temp3=fun5(10) --支持多个变量来接取返回值
print(temp1)
print(temp2)
print(temp3)    --nil

5.匿名函数

lua 复制代码
fun2=function()
	print("my fun2")
end
 
fun2()

6.可变形参函数

lua 复制代码
function fun7(...)
	arg={...}        --arg表存储参数
	for i=1,#arg do
		print(arg[i])
	end
end
fun7(1,2,3,4,"hello",false)

7.获取函数类型

lua 复制代码
fun6=function()
	print("my fun6")
end
print(type(fun6))   --function

8.函数嵌套

lua 复制代码
function fun8()
	return function()
		print("函数嵌套")
	end
end
 
--调用方式1
fun9=fun8()
fun9()
--调用方式2
fun8()()

9.函数嵌套-闭包

在Lua中,函数可以嵌套在其他函数内部,这时候内部的函数可以访问外部函数的局部变量,这种结构称为闭包(closure)。闭包的强大之处在于,即使外部函数的执行已经结束,闭包仍然可以记住外部函数中的变量。

lua 复制代码
function fun10(x)
	return function(y)
		print(x+y)    --临时变量x的生命周期变长
	end
end
 
close=fun10(1)
close(2)

2.4 table

表是 Lua 中唯一的数据结构,可以用来表示数组、字典等复杂数据结构。表在 Lua 中是非常强大的,因为它们可以包含所有类型的值。

1.一维数组

lua 复制代码
a={1,2,3,4,nil,true,"hello",nil} --8个元素     如果数组的最后一个元素是 nil,Lua 通常会将其视为数组的结束,导致长度计算时忽略该 nil 元素。
print("数组a的长度:"..#a)  --7      lua5.1.5版本中,nil如果是数组最后一个元素,计算数组长度时则会忽略该元素。用#获计算长度不准确
print(a[0]) --nil  lua索引从1开始
print("第一个元素:"..a[1]) --1
 
print("---------------一维数组遍历")
for i=1,#a do
	print(a[i])
end

2.unpack函数

在Lua中,unpack函数是一个非常有用的内置函数,它可以从表中取出一个连续的序列,并返回这些值。这个函数在Lua 5.1中是全局的,但从Lua 5.2开始,它被移到了table库中,即table.unpack。

lua 复制代码
a = {1,2,3,4,nil,true,"hello",nil} 
print(unpack(a))  --1	2	3	4	nil	true	hello

使用unpack可以很方便地将表中的值作为多个参数传递给函数。

unpack或table.unpack接受三个参数:表、起始索引和结束索引。如果不指定起始索引和结束索引,默认情况下它会从第一个元素开始,到表的长度结束。

3.二维数组

lua 复制代码
a={{1,2,3},{4,nil,"hello"}}
print(a[1][3]) --3
print(a[2][3]) --hello
 
print("---------------二维数组遍历")
for i=1,#a do
	b=a[i]
	for j=1,#b do
		print(b[j])
	end
end

4.自定义索引

Lua的表不仅可以使用整数索引(不建议自定义整数索引),还可以使用字符串或其他Lua值(除了nil)作为键。

lua 复制代码
a={[0]=1,2,3,[-1]=4,[4]=5}
print(#a)   --2   会去除索引不正常的元素
print(a[0]) --1
 
for i=1,#a do
	print(a[i])  --2 3
end
 
a={[1]=1,[2]=1,[4]=1,[6]=1}
print(#a)   --6
print(unpack(a)) --1	1	nil	1	nil	1

5.迭代器遍历

使用#计算长度并不准确,建议使用迭代器遍历:

  • 如果想要处理的是严格意义上的数组(索引连续的列表),使用ipairs更合适,因为它的性能可能会更好一些。
  • 如果需要处理的是一个混合了数组和字典风格的表,或者你不确定表的索引是否连续,那么使用pairs会更安全,它能确保遍历到表中的所有元素(nil除外)
lua 复制代码
a={[0]=0,1,2,3,nil,4,5,[10]=6,c=7,nil}
 
for i,k in ipairs(a) do
	print("i:"..i.."-k:"..k)
end
-- i:1-k:1
-- i:2-k:2
-- i:3-k:3
lua 复制代码
a={[0]=0,1,2,3,nil,4,5,[10]=6,c=7,nil}
 
for i,k in pairs(a) do
	print("i:"..i.."-k:"..k)
end
 
--i:1-k:1
--i:2-k:2
--i:3-k:3
--i:5-k:4
--i:6-k:5
--i:0-k:0
--i:10-k:6
--i:c-k:7

6.字典

在Lua中,并没有专门的"字典"类型,但是表(table)结构在Lua中是非常灵活的,通常用来实现类似字典的功能。表可以存储键值对,其中键和值可以是任意类型的数据(除了nil)。当使用字符串作为键时,表就类似于其他语言中的字典或哈希表。

lua 复制代码
a={["name"]="Lisa",["age"]=22,["sex"]="girl",["1"]=true,c=56}
 
print("-------------访问")
print(a["name"])
print(a.c)
print(a.name)--虽然可以通过这种方法得到值,但键不能是数字,如a.1不对
 
print("-------------修改")
a["age"]=20
print(a["age"])
 
print("-------------新增")
a["Country"]="TaiLand"
print(a.Country)
 
print("-------------删除")
a["Country"]=nil
print(a.Country)
 
print("-------------字典的遍历,使用pairs")
for i,k in pairs(a) do
	print(i,k)
end

7.类

Lua中默认没有面向对象,所以不能new。

lua 复制代码
Student={
	age=12,
	name="Lisa",
	fun0=function(t) --在函数中需要调用表本身的属性和方法时,可以把自己当参数传进来
		print("fun0:"..t.name..":"..t.age) 
	end,
	fun1=function()
		--print("fun1:"..name..":"..age) --错误
		print("fun1:"..Student.name..":"..Student.age) --在函数中调用表本身的属性和方法,需要指明表名称
	end
}

--新增变量
Student.sex="girl"
 
print(Student.age)
print(Student.sex)
 
Student.fun0(Student)
Student:fun0() --语法糖:冒号调用方法时,会默认把调用者作为第一个参数传入方法中
Student.fun1()

类函数声明 :和普通函数申明的两种方式(普通函数、匿名函数)相同,除此之外,也可以使用:来申明。

  • 当声明一个方法时,使用 : 语法允许定义一个需要隐式 self 参数的函数。self 实际上指的是调用方法的对象实例,而不是类名。
  • 当调用一个方法时,如果使用 : 语法,Lua会自动将调用该方法的表(对象)作为第一个参数传递给该方法。
lua 复制代码
Student.fun2=function()
    print("fun2")
end
 
function Student.fun3()
	print("fun3")
end
 
function Student:fun4() --语法糖:冒号声明方法时,会默认把调用者作为第一个参数传入方法中。self表示默认传入的第一个参数,self不是this。(self 实际上指的是调用方法的对象实例,而不是类名)
	print("fun4:"..self.name)
end
 
Student.fun2()
Student.fun3()
 
Student:fun4()
Student.fun4(Student)

8.表操作

操作 代码 备注
插入 insert
删除 remove 默认删除最后一个元素
排序 sort 排序操作会直接改变原始表,而不是创建一个已排序的新表。
拼接 concat table.concat函数用于将表中的元素连接成一个字符串。你可以指定一个连接符(也称为分隔符),用来在合并时插入元素之间。如果不指定连接符,默认使用空字符串(也就是没有分隔符)。 table.concat还可以接受第二个和第三个可选参数,分别代表起始索引和结束索引,用于指定连接表中的哪一部分。
lua 复制代码
t1={{name=1,age=10},{name=2,age=11}}
t2={name=3,age=12}
 
print(#t1)  --2
table.insert(t1,t2)
 
print(#t1)  --3
print(t1[3]["age"])  --12

table.remove(t1) --默认删除最后一个元素
table.remove(t1,1) --第二个参数,指定移除的元素索引

t3={12,53,6,2,4}
table.sort(t3)
print(unpack(t3)) --2	4	6	12	53

t4={1,"hello","world"}
str=table.concat( t4, "-", 1, 3 )
print(str) --1-hello-world

2.5 协程

Lua中的thread类型是指协同程序(coroutines),它们是由coroutine库提供的。在Lua中,术语"thread"通常指的是这些协同程序,而不是操作系统级别的线程。Lua的协同程序是协作式的,而非抢占式的,这意味着它们不会自行中断以让其他线程运行,而是显式地通过yield和resume来交换控制权。(Lua的线程可以让你编写出看起来像是同时执行的代码,但实际上它们是分时执行的,一个线程让出控制权后,另一个线程才会开始执行。)

复制代码
Unity 协程是与引擎的事件循环集成在一起的,允许在等待时继续处理其他事件和渲染更新。这与 Lua 中需要显式地调用 coroutine.resume 来恢复协程的执行有很大的不同。在 Unity 中,你只需要启动协程,引擎会在合适的时间点自动恢复它的执行。 Lua中使用coroutine.create创建协程,每执行一次coroutine.resume,协程函数会前进至下一个coroutine.yield。

1.协程创建

  • coroutine.create():常用方式,返回线程类,协程的本质是线程对象
lua 复制代码
fun=function()
	print("hello 0223")
end
co=coroutine.create(fun)
print(type(co)) --thread 
  • coroutine.wrap():返回函数类型
lua 复制代码
fun=function()
	print("hello 0223")
end
 
co1=coroutine.wrap(fun)
print(type(co1))--function

2.协程运行

对应两种创建方式,协程运行也不同:

  • coroutine.resume:对应create创建方式
  • 按函数方式运行
lua 复制代码
coroutine.resume(co)  --对应create创建方式
 
co1() --按函数方式运行

3.协程挂起

lua 复制代码
fun2=function ()
	local i=1
	while true do
		print(i)
		i=i+1
		--挂起
		coroutine.yield(i) --返回i
	end
end
 
co2=coroutine.create(fun2)
 
temp1,temp2=coroutine.resume(co2) 
print(temp1,temp2) --true 	2     --true表示协程运行成功,temp2才是返回值i
 
temp1,temp2=coroutine.resume(co2) --运行一次执行一次
print(temp1,temp2) --true	3

4.协程状态

  • coroutine.status(co)返回协同程序co的状态,可能的值有running、suspended、normal和dead。

  • coroutine.running() 得到正在运行的协程编号,要在函数内部打印。

    复制代码
     coroutine.wrap 返回的是一个函数,而不是协程对象,所以不能对它使用 coroutine.status。因为 coroutine.status 期望它的参数是一个协程,而不是一个函数。
lua 复制代码
fun=function()
	print("hello 0223")
	print(coroutine.running()) 
end
co=coroutine.create(fun)
coroutine.resume(co)
print(coroutine.status(co)) 
 
-- hello 0223
-- thread: 00D5E500
-- dead
lua 复制代码
fun=function()
	print("hello 0223")
	print(coroutine.running()) 
	coroutine.yield("hello")
end
co=coroutine.create(fun)
coroutine.resume(co)
print(coroutine.status(co)) 
 
-- hello 0223
-- thread: 00C9DD90
-- suspended
相关推荐
重生之我是Java开发战士1 小时前
【Java SE】TCP/IP协议栈:从分层架构到核心机制
java·tcp/ip·架构
CoderYanger1 小时前
递归、搜索与回溯-综合练习:22.优美的排列
java·算法·leetcode·深度优先·1024程序员节
张人大 Renda Zhang1 小时前
Maven = Java 构建世界的“事实标准”:从 pom.xml 到云原生 CI/CD
xml·java·spring boot·后端·ci/cd·云原生·maven
shayudiandian1 小时前
【Java】内部类
java
老鼠只爱大米1 小时前
Java设计模式之装饰器模式详解
java·设计模式·装饰器模式·decorator·java设计模式
0***v7771 小时前
springboot 异步操作
java·spring boot·mybatis
LSL666_1 小时前
7 SpringBoot pom.xml解释
java·spring boot·spring
ps酷教程1 小时前
java泛型反射&mybatis的TypeParameterResolver
java·mybatis
b***59431 小时前
springboot+mybaties项目中扫描不到@mapper注解的解决方法
java·spring boot·mybatis