Lua Study Notes
什么是 lua
Lua 是一个小巧的脚本语言。是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组,由 Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo 所组成并于 1993 年开发。
其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。Lua 由标准 C 语言 编写而成,几乎在所有操作系统和平台上都可以编译,运行。Lua 并没有提供强大的库,这是由它的定位决定的。所以 Lua 不适合作为开发独立应用程序的语言。Lua 有一个同时进行的 JIT 项目,提供在特定平台上的即时编译功能。
Lua 脚本可以很容易的被 C 语言和 C++ 代码调用,也可以反过来调用 C/C++ 的函数,这使得 Lua 在应用程序中可以被广泛应用。不仅仅作为扩展脚本,也可以作为普通的配置文件,代替 XML,ini 等文件格式,并且更容易理解和维护。
Lua 由标准 C 编写而成,代码简洁优美,几乎在所有操作系统和平台上都可以编译,运行。 一个完整的 Lua 解释器不过 200k,在目前所有脚本引擎中,Lua 的速度是最快的。这一切都决定了 Lua 是作为嵌入式脚本的最佳选择。
安装 lua or luajit
$ brew install luajit
$ luajit -v
LuaJIT 2.1.0-beta3 -- Copyright (C) 2005-2022 Mike Pall. https://luajit.org/
$ brew install lua@5.3
$ brew link lua@5.3
$ lua -v
Lua 5.3.6 Copyright (C) 1994-2020 Lua.org, PUC-Rio
Lua 官方网站:https://www.lua.org/
Luajit 官方网站:https://luajit.org/
lua 与 luajit 的区别
Lua 和 LuaJIT 是两种不同的解释器,它们都是基于 Lua 语言的,但是它们有一些不同之处。
LuaJIT 比 Lua 更快:LuaJIT 是一个 JIT(Just-In-Time)编译器,它可以在运行时将 Lua 字节码编译成本地机器代码,这使它比 Lua 更快。在许多基准测试中,LuaJIT 比 Lua 快得多。
LuaJIT 有更好的内存管理:LuaJIT 的内存管理器比 Lua 更高效。它可以在更小的内存占用下执行更多的操作。这使得 LuaJIT 比 Lua 更适合用于高负载的应用程序。
LuaJIT 的兼容性存在问题:由于 LuaJIT 使用了一些与 Lua 不兼容的优化技术,因此在某些情况下,LuaJIT 可能无法与使用标准 Lua 的代码库兼容。
总的来说,LuaJIT 是一个非常快速和高效的 Lua 解释器,但它的兼容性比 Lua 更差。如果您需要速度和效率,那么 LuaJIT 可能是更好的选择,但如果您需要兼容性和稳定性,则应该选择 Lua。
Lua 基本语法
关键词
注释
行注释
-- comment
块注释
--[[ 这里是注释 ]] -- 推荐 --[[ print("Hello world") --]]
注意
--
与[[
之间没有空格
数据类型
数据类型 描述 nil 这个最简单,只有值 nil 属于该类,表示一个无效值(在条件表达式中相当于 false)。 boolean 包含两个值:false 和 true。 number 表示双精度类型的实浮点数。 string 字符串由一对双引号或单引号来表示。 table Lua 中的表(table)其实是一个 “关联数组”(associative arrays),数组的索引可以是数字或者是字符串。在 Lua 里,table 的创建是通过 “构造表达式” 来完成,最简单构造表达式是 {},用来创建一个空表。 function 由 C 或 Lua 编写的函数。 thread 表示执行的独立线路,用于执行协同程序。 userdata 表示任意存储在变量中的 C 数据结构。
Lua 运算符
在 Lua 中,常见的运算符有以下几种:
算术运算符:用于进行基本的数值运算,包括加减乘除等。例如,+表示加法,-表示减法,*表示乘法,/表示除法,%表示取模(取余数)运算。
比较运算符:用于比较两个值的大小,进行逻辑判断。例如,==表示等于,~=表示不等于,>表示大于,<表示小于,>=表示大于等于,<=表示小于等于。
逻辑运算符:用于进行逻辑运算,包括与、或、非等。例如,and 表示逻辑与,or 表示逻辑或,not 表示逻辑非。
字符串连接运算符:用于连接两个字符串。例如,..表示连接运算符。
下面是一个示例代码,演示了常见的 Lua 运算符的用法:
a = 5
b = 3
c = a + b
d = a / b
e = a % b
f = a * b
g = a - b
print(c, d, e, f, g) -- 输出8 1.6666666666667 2 15 2
-- 比较运算符
if a == b then
print("a等于b")
elseif a > b then
print("a大于b")
else
print("a小于b")
end -- 输出a大于b
-- 逻辑运算符
x = true
y = false
if x and y then
print("x和y都为真")
elseif x or y then
print("x或y至少有一个为真")
else
print("x和y都为假")
end -- 输出x或y至少有一个为真
-- 字符串连接运算符
str1 = "hello"
str2 = "world"
str3 = str1 .. " " .. str2
print(str3) -- 输出hello world
当我们运行上述代码时,会输出各种运算符的结果以及相关的提示信息。
Lua 流程控制
在 Lua 中,常见的流程控制语句包括条件语句和循环语句。下面是一些示例代码,演示了如何使用这些流程控制语句:
- 条件语句
条件语句用于根据某个条件的真假来执行不同的操作。在 Lua 中,条件语句使用 if..then 语法。下面是一个示例代码:
x = 10
if x > 0 then
print("x是正数")
elseif x == 0 then
print("x是零")
else
print("x是负数")
end
在这个示例代码中,我们使用了 if..then 语句来判断 x 的大小,并打印相应的提示信息。
- 循环语句
循环语句用于多次执行某个操作。在 Lua 中,常见的循环语句包括 while 循环和 for 循环。下面是一些示例代码:
x = 0
while x < 10 do
print(x)
x = x + 1
end
-- for循环
for i = 1, 10 do
print(i)
end
在这个示例代码中,我们使用了 while 循环和 for 循环来分别输出 0 到 9 和 1 到 10 之间的整数。
除了基本的条件语句和循环语句外,Lua 还支持 break 和 return 语句来跳出循环或函数,并且可以使用 repeat..until 语句进行至少执行一次的循环。
- break 语句
break 语句用于在循环中提前跳出循环。下面是一个示例代码:
for i = 1, 10 do
if i == 5 then
break
end
print(i)
end
在这个示例代码中,我们使用了 for 循环来输出 1 到 4 之间的整数,并在 i 等于 5 的时候使用 break 语句提前跳出循环。
- repeat..until 语句
repeat..until 语句用于至少执行一次循环,直到某个条件成立时跳出循环。下面是一个示例代码:
x = 0
repeat
print(x)
x = x + 1
until x > 10
在这个示例代码中,我们使用了 repeat..until 语句来至少输出一次 0,并在 x 大于 10 的时候跳出循环。
除了基本的流程控制语句外,Lua 还可以使用 goto 语句来直接跳转到代码中的某个位置,但是使用 goto 语句可能会使代码变得难以理解,因此不建议滥用。
- return 语句
return 语句用于从函数中返回一个值,并结束函数的执行。下面是一个示例代码:
function add(x, y)
return x + y
end
z = add(3, 4)
print(z)
在这个示例代码中,我们定义了一个函数 add,用于计算两个数的和,并使用 return 语句返回运算结果。在主程序中,我们调用了这个函数,并把它的结果赋给变量 z,并输出 z 的值。
需要注意的是,如果在函数中使用了 return 语句,那么这个语句后面的代码将不会被执行,因为函数的执行已经结束了。
综上所述,Lua 中的流程控制语句包括条件语句和循环语句,以及 break 和 return 语句等。这些语句可以让我们根据不同的情况来执行不同的操作,并且可以循环执行某个操作,或者提前跳出循环等。需要根据具体的应用场景来选择合适的流程控制语句,以提高代码的效率和可读性。
Lua 数组
Lua 函数
Lua 字符串
Lua 迭代器
在 Lua 中,迭代器是一种非常方便的编程工具,它可以让我们遍历某个数据集合中的所有元素,而无需知道该集合的内部实现方式。下面是一个简单的迭代器示例代码:
function my_iterator(data)
local index = 1
return function()
local value = data[index]
if value ~= nil then
index = index + 1
return value
end
end
end
my_data = {1, 2, 3, 4, 5}
for value in my_iterator(my_data) do
print(value)
end
这个代码片段定义了一个名为 my_iterator 的函数,它接受一个数据集合 data 作为参数,并返回一个匿名函数。当这个匿名函数被调用时,它会返回当前数据集合中的下一个元素,直到所有元素都被遍历完毕。
在最后一行代码中,我们使用 for 循环遍历 my_iterator 函数返回的迭代器对象,并打印每个元素的值。
当我们运行上述代码时,会输出 data 表中的每个元素,即 1,2,3,4,5。
Lua Table
Lua 模块与包
Lua 中,模块是一种封装代码的方法。在 Lua 中,一个模块通常包含一些相关的函数和数据,可以被其他 Lua 程序引用和使用。通常,一个模块存放在一个单独的 Lua 文件中,并且在其他 Lua 程序中通过 require 函数进行引用。在一个 Lua 程序中,一个模块只会被加载一次,这样可以避免重复定义变量和函数。
在 Lua 中,一个包通常是一个由多个模块组成的集合。一个包可以包含一个 init.lua 文件,用于初始化整个包。当一个包被引用时,init.lua 文件会被自动执行。
在 Lua 中,模块和包是非常常用的代码组织方式,可以帮助我们将代码封装和组织得更加清晰和易于维护。
Lua 元素
Lua 协程
Lua 协程指的是一种轻量级的线程,它允许我们在同一线程内切换执行上下文,从而实现异步编程的目的。Lua 协程的实现是基于对协程的手动管理,即使用 coroutine 库中的相关函数来创建、启动、暂停、恢复和销毁协程。
- 在 Lua 中,我们可以使用 coroutine.create()函数来创建一个协程,使用 coroutine.resume()函数来启动一个协程,使用 coroutine.yield()函数来暂停一个协程并返回值,使用 coroutine.status()函数来查询协程的状态。
- 当协程结束或者出现错误时,我们可以从 coroutine.resume()函数中获取返回值或错误信息。
Lua 协程可以用于很多场合,比如实现异步 IO、控制协程的执行顺序、实现状态机等。因为它的实现是基于对协程的手动管理,所以需要开发人员对协程的使用和管理比较熟练才能写出效果好、易维护的代码。
Lua 文件读写
在 Lua 中,我们可以通过 io 库来进行文件的读写操作。下面是一些常用的文件读写操作函数:
io.open(filename, mode):打开一个文件,其中 filename 是要打开的文件名,而 mode 是打开模式,包括"r"(读取模式)、“w”(写入模式)和"a"(追加模式)等。
file:read(format):从文件中读取数据,其中 format 是读取模式,包括"*n"(读取一个数字)、"*a"(读取整个文件)和"*l"(读取一行)等。
file:write(…):向文件中写入数据,其中"…“表示要写入的数据,可以是任意数量的参数。
file:close():关闭文件。
下面是一个简单的读取文件的示例代码:
local file = io.open("test.txt", "r")
local content = file:read("*all")
print(content)
file:close()
这个代码片段会打开名为 test.txt 的文件,然后使用 read 函数读取整个文件的内容,最后打印出来。最后,记得要关闭文件。