1 数据类型
Lua 语言提供了丰富的数据类型,用于处理各种数据。主要包含以下八种类型:

- 字符串(string):由双引号或者单引号括起来的字符序列。
- 数值类型(number):涵盖所有数字形式,包括十进制、十六进制以及科学计数法等表示方法。
- 布尔类型(boolean):仅包含真和假两个值,分别对应 true 和 false。
- 函数(function):封装了特定功能的代码块,可作为值传递。
- 表(table):Lua 语言的核心数据结构,类似于哈希表,用于存储关联数据。
- 自定义类型(userdata):由应用程序定义的类型,脚本用户只能使用,不能直接定义其结构。
- 线程(thread):表示协同程序,用于实现异步计算,是一种轻量级有限线程。
- 空类型(nil):表示“空”或“无”,代表变量没有值。
在 Lua 编程中,可以使用 type 函数来查询并确定变量当前的数据类型。
理解这些基础类型是掌握 Lua 编程的关键,它们构成了所有数据操作的基础。
2 字符串(string)
在 Lua 中,双引号和单引号括起来的字符串在使用上没有区别,两者均支持对转义字符进行正确转义处理。

此外,字符串还可以使用两个成对的中括号([[ ]])来包含。这种方式用于存储字符串的原始值,即使字符串内容跨越多行,也能保持原样,非常适合处理大段文本或包含特殊字符的字符串。
3 数值类型(number)
数值类型涵盖了 Lua 中所有的数字表示形式。这包括常见的十进制整数、浮点数,以及十六进制表示法和科学计数法表示的数值。Lua 内部通常将数值统一处理为双精度浮点数,以支持广泛的数学运算。
4 布尔类型(boolean)
布尔类型是最简单的数据类型之一,仅包含两个预定义的值:true(真)和 false(假)。它们常用于条件判断和控制流语句中,决定代码的执行路径。
5 表(table)
表是 Lua 中最重要的数据结构,用来存储互相关联的元素。每个元素由一个关键字(key)和一个值(value)组成,形成键值对结构。表的功能类似于其他语言中的哈希表或字典。
表中元素的值可以是任何类型的值,包括字符串、数值、其他表、函数等,这使得表具有极高的灵活性和扩展性。
对表中元素的引用,除了使用 表名[键名] 语法之外,还可以使用 表名.键名 语法。需要注意的是,后面这种点号引用方式不可以引用键是数值的元素,而方括号方式则更为通用。
5.1 全局表 _G
在 Lua 中,所有定义的全局变量都会自动存储在一个名为 _G 的特殊表中。这个全局表充当了全局命名空间的容器,使得我们可以通过访问该表的键来读取或修改变量的值。这种机制不仅简化了全局变量的管理,也为动态访问变量提供了便利。例如,通过 _G 表,我们可以动态地获取或设置任意全局变量的值,这在编写通用工具函数或框架时非常有用。
5.2 复制表方式实现面向对象
Lua 虽然没有内置的类概念,但可以通过表来模拟面向对象编程。由于表可以存储键值对,并且可以将函数赋值给表的键,因此我们可以将表视为一个类。通过这种方式,我们可以定义类的属性和方法,并创建该类的实例。
为了实现对象的创建,我们可以定义一个函数,用于克隆上面定义的 Person 表的元素。这个函数会生成一个新的表,模拟生成新对象的过程。通过这种方式,我们可以创建多个具有相同属性和方法的对象实例,从而实现面向对象编程的基本功能。
此外,我们可以在表 Person 中定义一个名为 new 的函数。这个函数可以接收参数,从而构造具有指定参数的对象。例如,我们可以定义一个构造函数,接收姓名和年龄作为参数,并返回一个新的对象表。这种方式使得对象的创建更加灵活和可控。
除了基本的对象创建,我们还可以模拟类之间的继承关系。通过将一个类的表作为另一个类的父表,我们可以实现属性的继承和方法的重写。这种方式使得代码更加模块化和可复用,符合面向对象编程的设计原则。
5.3 函数闭包方式实现面向对象
另一种实现面向对象编程的方式是使用函数闭包。我们可以定义一个函数,该函数返回一个表(对象),并通过闭包机制保留局部变量的状态。这种方式使得对象的内部状态更加安全,因为外部无法直接访问这些局部变量。
例如,我们可以定义一个函数,该函数创建一个包含私有变量的表,并返回一个包含方法的表。这些方法可以访问和操作私有变量,从而实现封装的效果。通过这种方式,我们可以实现更加复杂的面向对象结构。
同样,模拟类继承关系也可以使用函数闭包的方式。通过将一个类的闭包函数作为另一个类的父函数,我们可以实现属性的继承和方法的重写。这种方式使得代码更加灵活,同时也保持了面向对象编程的核心思想。
6 函数
函数的基本特性与返回值
在 Lua 中,函数被视为 function 类型的对象。这一特性赋予了函数极高的灵活性:它们可以被赋值给变量,能够作为其他函数的返回值,支持相互比较,并且可以作为 table 表中的值存储。这种一等公民的地位使得函数在 Lua 编程中扮演着核心角色。
Return 关键字的使用规则
函数可以选择不返回值,也可以返回单个值或多个值。需要注意的是,return 关键字的使用位置受到严格限制,它只能出现在代码块的末尾,具体而言,必须位于 end、else 或者 until 关键字之前。这一规则确保了控制流的清晰性和代码的可读性。
多值返回与赋值机制
Lua 处理函数返回值时遵循特定的规则。如果函数的返回值是另一个函数的最后一个参数,或者是多值赋值表达式中的最后一个参数,那么该函数的所有返回值都会被保留并使用。反之,如果不符合上述条件,则只有第一个返回值会被使用,其余返回值将被丢弃。这一机制在处理复杂数据传递时尤为重要。
可变参数与尾调用优化
Lua 支持定义可变参数的函数,允许函数接收不定数量的参数。此外,当函数的最后返回值是调用另一个函数时,这种结构被称为尾调用。Lua 在实现尾调用优化时,会先弹出当前函数的栈空间,然后再调用目标函数。这种机制显著降低了函数层层调用过程中的栈消耗,特别适用于需要深度递归调用的场景,从而提高了程序的性能和稳定性。
本次分享到此结束啦~~
如果觉得文章对你有帮助,点赞、收藏、关注、评论,您的支持就是我创作最大的动力!
print(type("chenpi")) -- string
print(type(123)) -- number
print(type(true)) -- boolean
print(type(type)) -- function
print(type({})) -- table
> print('单引号括起来的字符串nr这是换行后内存!')
单引号括起来的字符串
这是换行后内存!
> print("双引号括起来的字符串nr这是换行后内存!")
双引号括起来的字符串
这是换行后内存!
>
str = [[aa
bb cc
dd
ee
ff ff ff
]]
print(str)
-- 输出结果如下
aa
bb cc
dd
ee
ff ff ff
i = 10
j = 10.15
k = 0x12
h = 1.20e5
print(i) -- 10
print(j) -- 10.15
print(k) -- 18
print(h) -- 120000.0
flag = true
if flag then
print("flag is true")
else
print("flag is false")
end
-- 输出 flag is true
-- 创建一个空表
t = {}
-- 没有显示指定键的值,系统会自动分配键1,2,3...
t = {k1 ="v1", "a", "b", "c"}
print(t[0]) -- nil
print(t[1]) -- a
print(t[2]) -- b
print(t[3]) -- c
print(t[4]) -- nil
print(t["k1"]) -- v1
t = {k1 ="a", "b", k2 = "c", "d"}
print(t[1]) -- b
print(t[2]) -- d
print(t["k1"]) -- a
print(t.k1) -- a
-- print(t.1) -- 不合法,会报错
t.k1 = "aa"
t[1] = "bb"
print(t[1]) -- bb
print(t.k1) -- aa
t = {k1 ="a", k2 = "b"}
print(t.k1) -- a
t.k1 = nil
print(t.k1) -- nil
t = {k1 ="a", "b", k2 = "c", "d"}
for k, v in pairs(t) do
print(k, v)
end
-- 输出结果如下
1 b
2 d
k2 c
k1 a
t = {}
t.func = function()
print("Hello ChenPi!")
end
function t.func()
print("Hello ChenPi!")
end
--[[
上面和此种方式一样,但是推荐使用上面的方式
function t.func()
print("Hello ChenPi!")
end
--]]
t.func() -- Hello ChenPi!
-- 插入元素,删除元素
table.insert(表名, 键, 值)
table.remove(表名, 键)
t = {"a", "b", "c"}
table.insert(t, 2, "g") -- 在第二个位置插入元素,原来键为2的值依次往后移
table.insert(t, "f") -- 没有指定键,则插入到尾部
-- 输出 agbcf
for i = 1, #t do
print(t[i])
end
table.remove(t, 2) -- 删除键为2的元素
table.remove(t) -- 省略键,则删除最后一个元素
-- 输出 abc
for i = 1, #t do
print(t[i])
end
-- 排序函数
table.sort(表名, 排序规则) -- 排序规则可以省略
t = {"d", "a", "e", "c", "h", "g"}
table.sort(t) -- 对值进行排序
-- 输出 acdegh
for i = 1, #t do
print(t[i])
end
function mysort(a, b)
return a > b
end
table.sort(t, mysort)
-- 输出 hgedca
for i = 1, #t do
print(t[i])
end
-- 定义一个空表
chenpifunc = {}
-- 定义第一个函数
chenpifunc.func1 = function()
print("Hello ChenPi!")
end
-- 定义第二个函数
chenpifunc.func2 = function(a, b)
local r = a + b
return r
end
-- 使用函数库
chenpifunc.func1()
print(chenpifunc.func2(5, 8))
-- 输出结果如下
Hello ChenPi!
13
arr = {1, 2, "a", "b", 3, true, 10.51}
-- 打印的数数组的地址
print(arr)
-- 遍历数组
for k, v in pairs(arr) do
print(k, v)
end
-- 打印数组类型
print(type(arr))
-- 输出结果如下
table: 0x2406730
1 1
2 2
3 a
4 b
5 3
6 true
7 10.51
table
name = "陈皮"
age = 18
print(_G["name"]) -- 陈皮
print(_G.age) -- 18
t = {name = "Hello Lua"}
func = function()
print("Hi func")
end
print(_G["t"]["name"]) -- Hello Lua
_G.func() -- Hi func
-- 定义一个表,代表一个类模板
Person = {}
Person.name = "ChenPi"
Person.eat = function(p)
print(p.name.." is eating")
end
print(Person.name) -- ChenPi
Person.eat(Person) -- ChenPi is eating
function clone(t)
local inst = {}
for k, v in pairs(t) do
inst[k] = v
end
return inst
end
-- 定义一个表,代表一个类模板
Person = {}
Person.name = "ChenPi"
Person.eat = function(p)
print(p.name.." is eating")
end
-- 克隆对象
local p = clone(Person)
print(p.name) -- Hi ChenPi
p.eat(p) -- I am eating
p:eat() -- I am eating 等同于调用eat函数,并把自身作为参数传入函数
function clone(t)
local inst = {}
for k, v in pairs(t) do
inst[k] = v
end
return inst
end
-- 定义一个表,代表一个类模板
Person = {}
Person.name = "ChenPi"
Person.eat = function(p)
print(p.name.." is eating")
end
Person.new = function(name)
local self = clone(Person)
self.name = name
return self
end
-- 克隆对象
local p = Person.new("陈皮")
print(p.name) -- 陈皮
p:eat() -- 皮 is eating
function clone(t)
local inst = {}
for k, v in pairs(t) do
inst[k] = v
end
return inst
end
-- 定义一个表,代表一个类模板
Person = {}
Person.name = "ChenPi"
Person.eat = function(p)
print(p.name.." is eating")
end
Person.new = function(name)
local self = clone(Person)
self.name = name
return self
end
-- 子类定义
Student = {age = 18}
Student.study = function()
print("Student is studying...")
end
Student.new = function(name)
local self = Person.new(name)
-- 将子类的元素放入父类中,重复的键还可以达到重写作用
for k, v in pairs(Student) do
self[k] = v
end
return self
end
-- 创建子类对象
local s = Student.new("陈皮")
print(s.name) -- 陈皮
print(s.age) -- 18
s:eat() -- 陈皮 is eating
s.study() -- Student is studying...
function Person(name)
local self = {}
self.name = name
self.eat = function(p)
print(p.name.." is eating")
end
return self
end
local p = Person("陈皮")
p:eat() -- 陈皮 is eating
function Person(name)
local self = {}
self.name = name
self.eat = function(p)
print(p.name.." is eating")
end
return self
end
local p = Person("陈皮")
p:eat() -- 陈皮 is eating
function Student(name)
local self = Person(name)
self.study = function()
print(self.name.." is studying...")
end
return self
end
local s = Student("狗蛋")
s:eat() -- 狗蛋 is eating
s.study() -- 狗蛋 is studying...
-- 函数定义1
function 函数名(参数)
函数内容
...
end
-- 例如
function sum( i, j)
return i + j
end
print(sum(10, 23)) -- 函数调用
-- 函数定义2
函数名 = function(参数)
函数内容
...
end
-- 例如
sum = function(i, j)
return i + j
end
print(sum(10, 23)) -- 函数调用
function chenpi()
print("no return") -- no return
end
chenpi()
function chenpi()
return "one return"
end
print(chenpi()) -- one return
function chenpi(a, b)
local x = a + b
local y = a - b
return x, y
end
i, j = chenpi(10, 5)
print(i) -- 15
print(j) -- 5
function func()
local x, y, z = 1, 2, 3
return x, y, z
end
print("Hello", "ChenPi", func()) -- Hello ChenPi 1 2 3
print("Hello", func(), "ChenPi") -- Hello 1 ChenPi
a, b, c, d = 0, func() -- 0 1 2 3
a, b, c, d = func(), 4 -- 1 4 nil nil
function 函数名(...) -- 三个点代表参数个数不确定
function 函数名(a, b, ...) -- 2个固定参数,其他参数不确定
function 函数名(a, ...) -- 1个固定参数,其他参数不确定
-- 假设定义如下函数
function chenpi(a, b, ...)
print(a)
print(b)
print(arg[1])
print(arg[2])
print("-------")
end
chenpi() -- a=nil,b=nil,arg={}
chenpi(1) -- a=1,b=nil,arg={}
chenpi(1, 2) -- a=1,b=2,arg={}
chenpi(1, 2, 3) -- a=1,b=2,arg={3}
chenpi(1, 2, 3, 4) -- a=1,b=2,arg={3,4}
-- 输出结果如下
nil
nil
nil
nil
-------
1
nil
nil
nil
-------
1
2
nil
nil
-------
1
2
3
nil
-------
1
2
3
4
-------
-- 以下函数调用耗时比较久
function func(i)
while i < 15 do
i = i + 1
print(i)
func(i)
end
return i
end
func(0)
-- 改变顺序,使用尾调函数,执行速度很快(而且1000还比15次数大很多)
function func(i)
if i > 1000 then
return i
end
i = i + 1
print(i)
func(i) -- func(i) + 1 不算尾调函数
end
func(0)
table
语句块的结尾一句
函数尾调用
尾调函数







