Lua 简介 Lua 的历史与发展 ⭐⭐ 起源 (1993): Lua的首个版本发布于1993年, 最初是为游戏行业设计的, 旨在提供一个易于嵌入应用程序中的轻量级脚本语言。
⭐⭐ Lua 1.x系列: 在1.x系列中, Lua逐渐增加了更多的功能, 并且开始吸引更多的开发者关注。
⭐⭐ Lua 2.x系列: 该系列版本引入了面向对象编程的支持, 并且增强了其作为通用脚本语言的功能。
⭐⭐ Lua 3.x系列 (1996): Lua 3.0是一个重要的里程碑, 它完全重写了之前的版本, 简化了API并移除了对宿主程序的依赖。 这次更新也引入了一些新的特性, 如尾调用优化。
⭐⭐ Lua 4.x系列 (1999): Lua 4.0继续发展, 增加了一些新特性, 如模块支持等, 但这个版本并没有广泛传播。
⭐⭐ Lua 5.x系列 (2003):
Lua 5.0引入了垃圾回收机制, 并且进一步改进了语言的设计。 从这个版本开始, Lua变得更为成熟稳定。
Lua 5.1 (2005) 是一个非常稳定的版本, 它改善了性能并且增强了错误处理机制。
Lua 5.2 (2012) 增加了对长整型的支持, 并且改进了错误报告机制。
Lua 5.3 (2014) 改进了内存管理, 并且支持64位整数和尾调用优化。
Lua 5.4 (2020) 引入了新的特性, 如模块加载器、 尾调用优化以及对Unicode的支持。
Lua 5.5 (2023) 是最新的稳定版本之一, 继续改进性能和安全性, 并添加了新的语言特性。
⭐⭐ 版本分支
LuaJIT (2005): 这是一个即时编译器( Just-In-Time Compiler) , 可以显著提高Lua代码的执行速度。 LuaJIT支持Lua 5.1语法, 并且可以运行在多种平台上。
Lua 5.1: 这是Lua的一个非常流行且稳定的版本, 许多现有的Lua应用和库都是基于此版本开发的。
其他分支: 还有一些其他分支和变种, 例如LuaRt, 它是专门为实时操作系统设计的Lua版本。
Lua 的应用领域 ⭐⭐ 游戏开发: Lua 因其轻量级、 易嵌入的特性, 在游戏开发中非常受欢迎。 它可以用于编写游戏逻辑、 AI、 配置文件等, 而且很多游戏引擎都支持 Lua, 如 Corona SDK、 LÖVE 和一些专有的游戏引擎。 著名的游戏如《 魔兽世界》 、 《 侠盗猎车手》 系列、 《 文明》 系列等都使用了 Lua。
⭐⭐ Web 开发: Lua 也可以用于 Web 应用程序的开发, 尤其是在需要高性能的情况下。 例如, OpenResty 是一个基于 Nginx 和 Lua 的平台, 常用于构建高性能的 Web 应用和服务。
Lua 在网络编程方面也有应用, 比如 LuaSocket 库提供了网络通信的功能。
⭐⭐ 嵌入式系统: 由于 Lua 的轻量级特性, 它可以被嵌入到各种嵌入式设备中, 用于设备管理和控制。
Lua 也被用于物联网(IoT)设备上, 帮助实现简单的脚本控制。
⭐⭐ 配置文件: Lua 的简单语法使其非常适合用来编写配置文件。 有些软件和应用程序选择 Lua 作为配置语言, 因为它既强大又容易理解。
⭐⭐ 桌面应用: Lua 可以用来编写桌面应用程序的脚本, 特别是在需要快速开发或原型设计的时候。
⭐⭐ 科学计算与工程: 在某些科学计算和工程应用中, Lua 也被用来处理数据和自动化任务。
⭐⭐ 图形用户界面(GUI): Lua 可以用来创建 GUI 应用程序, 尽管这并不是它的强项, 但仍有一些库如 LÖVE 提供了图形和GUI支持。
⭐⭐ 教育和教学: Lua 的简洁语法和相对容易的学习曲线使其成为教学编程概念的好工具, 尤其是对于初学者来说。
⭐⭐ 脚本自动化: Lua 常用于自动化任务, 比如编写系统管理脚本或在服务器环境中执行特定任务。
⭐⭐ 其他领域: Lua 在许多其他领域也有应用, 比如在音频处理、 视频编辑软件中作为扩展语言等。
环境搭建 安装 Lua 解释器 Windows 平台
访问官网: 前往 Lua 官方网站 www.lua.org 。
下载 Lua: 点击“ downloads” 或者“ 下载” 链接, 找到最新稳定版的 Lua( 如 Lua 5.4) , 下载 Windows 版本的安装包。
安装 Lua: 双击下载的安装包, 按照提示完成安装过程。 通常情况下, 你可以选择默认安装路径, 或者指定一个路径。
验证安装: 打开命令提示符窗口, 输入 lua, 如果看到 Lua 的命令行提示符 =, 则表示安装成功。
macOS/Linux 平台:
下载源码: 同样从 Lua 官网下载源码包。
解压源码包: 使用 tar 或者 unzip 工具解压下载的文件。
编译安装: 进入解压后的目录, 然后运行 make 编译 Lua, 之后运行 make install 进行安装。 这可能需要管理员权限。
验证安装: 打开终端, 输入 lua, 检查是否能够正常启动。
设置开发环境 Visual Studio Code 下载并安装 VS Code。
安装 Lua 扩展插件, 如 lua-vscode, 以获得更好的 Lua 支持, 包括语法高亮、 智能感知等功能。
Notepad++ 下载并安装 Notepad++。
启用 Lua 语言支持, 可以通过安装插件或手动设置来启用 Lua 语法高亮。
Sublime Text 下载并安装 Sublime Text。
通过 Package Control 安装 Lua 插件来增强 Lua 开发体验。
其他编辑器/IDE 如 IntelliJ IDEA, Eclipse, Vim, Emacs 等, 这些工具也都有相应的 Lua 支持插件或配置。
配置环境变量 如果希望在任何位置都能直接运行 Lua 脚本, 可以在系统环境变量中加入 Lua 的安装路径。
Windows 找到 Lua 的安装路径( 如 C:\Program Files\lua) 。
在系统属性中设置环境变量, 将 Lua 的 bin 目录添加到 PATH 环境变量中。
macOS/Linux 在用户的 .bashrc 或 .zshrc 文件中添加 export PATH=$PATH:/path/to/lua/bin, 然后运行 source .bashrc 或 source .zshrc 使设置生效。
测试 Lua 环境
创建一个简单的 Lua 文件( 如 test.lua) , 内容如下:
在命令行或终端中运行 lua test.lua, 如果能看到输出 “Hello, World!”, 说明一切正常。
基本语法 注释 单行注释 使用两个减号 – 来添加单行注释。
多行注释 使用两个减号加上一个左方括号 –[[ 和对应的右方括号 ]] 来添加多行注释。
数据类型 数字 1 2 3 local i = 42 local f = 3.14 local scientific = 1e4
字符串 字符串是字符序列, 可以用单引号、 双引号或者 [[ ]] 来定义。
1 2 3 local s1 = 'hello' local s2 = "world" local s3 = [[hello world]]
布尔值 布尔值有两种: true 和 false。
1 2 local b1 = true local b2 = false
Nil nil 是一种特殊的值, 用来表示没有值的状态。
Table Table 是 Lua 中的主要数据结构, 可以看作是数组或哈希表( 字典) 。 Table 可以用 {} 来创建, 并且可以存储任意类型的数据。
1 2 3 local t = {} local t2 = {1 , 2 , 3 } local t3 = {a=1 , b=2 }
运算符 算术运算符 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + 加法 - 减法 * 乘法 / 除法 ^ 幂运算 % 取模 local a = 10 local b = 5 print (a + b) print (a - b) print (a * b) print (a / b) print (a ^ 2 ) print (a % b)
关系运算符 1 2 3 4 5 6 7 8 9 10 11 12 == 等于 ~= 不等于 < 小于 > 大于 <= 小于或等于 >= 大于或等于 local x = 10 local y = 5 print (x == y) print (x > y) print (x ~= y)
逻辑运算符 1 2 3 4 5 6 7 8 9 and 逻辑与or 逻辑或not 逻辑非local a = true local b = false print (a and b) print (a or b) print (not a)
流程控制 条件语句 if 语句用于基于条件判断来决定是否执行一段代码。 可以使用 elseif 和 else 来提供额外的条件判断和默认情况。
1 2 3 4 5 6 7 8 local x = 10 if x < 0 then print ("x is negative" ) elseif x > 0 then print ("x is positive" ) else print ("x is zero" ) end
循环语句 💗💗 for 循环 Lua 支持两种形式的 for 循环: 数值循环和泛型循环。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 for i = 1 , 5 do print (i) end local t = {10 , 20 , 30 }for index, value in ipairs (t) do print (index, value) end for key, value in pairs (t) do print (key, value) end
💗💗 while 循环 while 循环会持续执行一段代码, 直到给定的条件不再为真。
1 2 3 4 5 local count = 1 while count <= 5 do print (count) count = count + 1 end
💗💗 repeat/until 循环 repeat 循环至少会执行一次, 然后检查条件, 如果条件为假, 则继续执行循环; 如果为真, 则终止循环。
1 2 3 4 5 local count = 1 repeat print (count) count = count + 1 until count > 5
函数 定义函数 在 Lua 中, 使用 function 关键字来定义一个函数。 函数可以带有参数, 并且可以有返回值。
1 2 3 function greet (name) print ("Hello, " .. name .. "!" ) end
调用函数 定义完函数后, 可以通过函数名后跟一对圆括号来调用它, 并传入必要的参数。
参数传递 值传递 在 Lua 中, 当你传递一个基本类型( 如数字、 字符串、 布尔值) 给函数时, 传递的是该值的拷贝。 因此, 在函数内部对该值所做的任何改变都不会影响到原始变量。
1 2 3 4 5 6 7 function increment (num) num = num + 1 end local x = 5 increment(x) print (x)
引用传递 当传递一个复合类型( 如 table 或者 userdata) 时, 实际上是传递了一个指向该对象的引用。 因此, 在函数内部对该对象所做的任何修改都会影响到原始对象。
1 2 3 4 5 6 7 function addOne (tbl) tbl.value = tbl.value + 1 end local t = {value = 5 }addOne(t) print (t.value)
返回值 Lua 中的函数可以返回多个值。 返回多个值时, 只需在 return 后面列出值即可。
1 2 3 4 5 6 function divide (dividend, divisor) return dividend / divisor, dividend % divisor end local quotient, remainder = divide(10 , 3 )print (quotient, remainder)
匿名函数 匿名函数是在定义时不赋予名称的函数。 可以立即定义并调用。
1 2 3 4 local result = (function (x) return x * x end )(5 )print (result)
闭包 闭包是指一个函数可以访问在其外部定义的作用域中的变量。 这种能力使得函数可以记住并访问其定义时的上下文。
1 2 3 4 5 6 7 8 function makeAdder (n) return function (x) return x + n end end local addFive = makeAdder(5 )print (addFive(10 ))
泛型函数 尽管 Lua 本身不支持真正的泛型编程( 如 C++ 或 Java 中的模板/泛型) , 但我们可以通过一些编程技巧来实现类似的功能。 泛型编程的核心思想是在不指定具体类型的情况下编写代码, 从而可以用于多种类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 local function printValue (value) if type (value) == "number" then print ("Number:" , value) elseif type (value) == "string" then print ("String:" , value) else print ("Unknown type:" , value) end end printValue(42 ) printValue("Hello" ) printValue({a=1 , b=2 })
泛型容器 可以定义一个泛型容器, 该容器可以存储任何类型的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 local function createContainer () local container = {} function container.setValue (value) container.value = value end function container.getValue () return container.value end return container end local c = createContainer()c:setValue("Hello" ) print (c:getValue())
错误处理 assert 函数 assert 函数用于断言某个条件为真, 如果条件不满足, 则抛出错误。
1 2 3 local x = tonumber (io .read ()) assert (x ~= nil , "Not a number" ) print (x)
pcall 函数 pcall( 保护调用) 允许你在发生错误时捕获异常而不中断程序执行。
1 2 3 4 5 6 7 local success, result = pcall (function () error ("This is an error message" , 2 ) end )if not success then print (result) end
xpcall 函数 xpcall 与 pcall 类似, 但是它允许你在错误发生时传递一个错误处理器函数。
1 2 3 4 5 6 7 8 9 10 11 local errHandler = function (err) print ("Caught error:" , err) end local success, result = xpcall (function () error ("This is an error message" , 2 ) end , errHandler)if not success then print (result) end
表( table) Lua 中的表( table) 是一种非常强大的数据结构, 可以被用作数组、 关联数组、 堆栈、 队列、 集合、 映射等。
创建空表
初始化表 1 2 3 4 5 local t = {"value1" , "value2" , "value3" }local t = {key1 = "value1" , key2 = "value2" }
访问表元素 可以通过索引来访问表中的元素, 下标从 1 开始。
1 2 local t = {10 , 20 , 30 }print (t[1 ])
修改表元素 直接通过索引赋值即可修改表中的元素。
表的遍历 使用 ipairs 遍历 ipairs 函数适用于遍历数组样式的表, 即那些索引为连续正整数的表。
1 2 3 4 5 6 7 8 9 local t = {"value1" , "value2" , "value3" }for i, v in ipairs (t) do print (i, v) end
使用 pairs 遍历 pairs 函数返回一个迭代器, 可以用来遍历表中的所有键值对。
1 2 3 4 5 6 7 8 local t = {key1 = "value1" , key2 = "value2" }for k, v in pairs (t) do print (k, v) end
使用 next 遍历 next 函数返回表中的下一个键值对。 通常配合循环使用来遍历整个表。
1 2 3 4 5 6 7 8 local t = {key1 = "value1" , key2 = "value2" }local k, v = next (t)while k do print (k, v) k, v = next (t, k) end
元表 元表是另一个表, 它定义了如何处理表的一些操作。 可以为一个表设置元表来改变其行为。
1 2 3 4 local t = {key1 = "value1" }local mt = {__index = _G } setmetatable (t, mt)
魔术方法 魔术方法是用来定义表的行为的特殊键值。 通过设置元表和使用魔术方法, 可以定制表的行为, 从而实现更复杂的数据结构和功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 local t = {}local mt = { __index = function (t, k) return k .. " has no value" end , __newindex = function (t, k, v) print ("Setting " .. k .. " to " .. v) end , __tostring = function (t) return "Custom tostring implementation" end } setmetatable (t, mt)print (t.key) t.key = "value" print (tostring (t))
面向对象 概念 在 Lua 中, 面向对象编程( OOP) 不是内置的语言特性, 而是通过 Lua 的元表机制和表的特性出来的。 一个“ 类” 本质上就是一个表, 包含了类的方法和属性。 对象则是这个类的一个实例, 也是一个表, 通常会包含类的属性。
类 在 Lua 中, 我们可以通过函数来创建“ 类” 。 这个函数通常会返回一个表, 这个表可以看作是类的原型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function MyClass () local self = setmetatable ({}, {__index = MyClass}) self .value = 0 return self end MyClass.method = function (self) print ("Method called with value:" , self .value) end local obj = MyClass()obj.method()
继承 在 Lua 中, 继承也是通过表的元表机制实现的。 子类可以继承父类的属性和方法。
通过设置子类的元表为父类, 子类就可以访问父类的方法和属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function MyBaseClass () local self = setmetatable ({}, {__index = MyBaseClass}) self .value = 0 return self end MyBaseClass.method = function (self) print ("Base method called with value:" , self .value) end function MyDerivedClass () local self = setmetatable ({}, {__index = MyBaseClass}) self .value = 10 return self end local derivedObj = MyDerivedClass()derivedObj.method()
多态 多态是指子类可以覆盖父类的方法, 表现出不同的行为。
1 2 3 4 5 MyDerivedClass.method = function (self) print ("Derived method called with value:" , self .value) end derivedObj.method()
接口 Lua 中并没有原生的接口( interface) 概念, 但是可以通过约定( convention) 和规范( specification) 来达到类似的效果。 例如, 定义一组必须的方法, 并确保每个对象实现了这些方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 local IShape = { draw = function (self) end } local Rectangle = {}setmetatable (Rectangle, {__index = IShape})Rectangle.draw = function (self) print ("Drawing a rectangle" ) end local rect = setmetatable ({}, {__index = Rectangle})rect:draw()
委托 Lua 中没有直接的委托( delegate) 概念, 但可以使用函数作为值来传递和存储, 从而实现类似的功能。 委托通常用于传递函数作为参数, 或者作为对象的回调方法。
1 2 3 4 5 6 7 8 9 local function myDelegate (callback) callback() end local function myCallback () print ("Callback was called" ) end myDelegate(myCallback)
协程 协程是一种比线程更轻量级的并发模型。 一个协程可以暂停执行, 并在适当的时候恢复执行。
1 2 3 4 5 6 7 8 9 local function coExample () print ("Coroutine started" ) coroutine .yield () print ("Coroutine resumed" ) end local co = coroutine .create (coExample)coroutine .resume (co) coroutine .resume (co)
模块化 在 Lua 中, 可以通过模块来组织代码, 使得代码更加模块化和易于维护。 一个模块通常是一个单独的文件, 它导出一系列的函数或变量。
创建模块 模块可以是一个简单的文件, 里面包含了一系列的函数定义。
1 2 3 4 5 6 7 8 local m = {}function m.greet (name) print ("Hello, " .. name .. "!" ) end return m
导入模块 在其他文件中, 可以通过 require 函数来导入模块。
1 2 3 4 local mod = require ('mymodule' ) mod .greet("Alice" )
热更新 热更新通常涉及到模块的重新加载。 在 Lua 中, 可以通过重新定义模块来实现热更新。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 local mod = {}mod .someFunction = function () print ("someFunction called" ) end return mod local mod = require ('mymodule' )mod :someFunction() package .loaded ['mymodule' ] = nil local newMod = require ('mymodule' )newMod:someFunction()
I/O操作 打开文件 在 Lua 中, 可以使用 io.open 函数来打开一个文件。 这个函数接受两个参数: 文件名和打开模式。
1 2 3 4 5 6 7 8 9 10 local file = io .open ("example.txt" , "w" )
关闭文件 关闭文件是很重要的, 因为它释放了文件资源, 并确保所有的缓冲数据都被写入磁盘。
写入文件 1 2 3 local file = io .open ("example.txt" , "w" )file:write ("Hello, World!\n" ) file:close ()
读取文件 1 2 3 4 5 6 7 8 9 10 11 12 local file = io .open ("example.txt" , "r" )local line = file:read ("*l" ) print (line) file:close ()
格式化输出 1 2 3 4 5 6 local number = 123 local formatted_string = string .format ("%d is the magic number\n" , number)local file = io .open ("example.txt" , "w" )file:write (formatted_string) file:close ()
标准输入输出 1 2 3 4 5 6 7 8 9 local input = io .stdin :read ("*l" )print ("You entered:" , input )io .stdout :write ("Output from program\n" )io .stderr :write ("Error message\n" )
完整示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 local file = io .open ("example.txt" , "w" )file:write ("Hello, World!\n" ) file:write (string .format ("The answer is %d\n" , 42 )) file:close () file = io .open ("example.txt" , "r" ) local content = file:read ("*a" )print (content)file:close ()
标准库 Lua 的标准库包含了一系列预定义的模块, 这些模块提供了丰富的功能, 可以帮助开发者处理各种常见的编程任务。
_G 表 _G 是一个全局环境表, 所有的全局变量都是 _G 表中的键值对。 这意味着你可以在 _G 表中直接访问或修改全局变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 _G .x = 10 print (_G .x) y = 20 print (_G .y) print (_G ["y" ]) _G .x = 15 print (x) _G .x = nil print (x) print (_G .math ) print (_G .os ) print (_G .print ) print (_G .string ) print (_G .table ) _G .myFunc = function () print ("Called myFunc" ) end myFunc() print ("Global variables:" )for k, v in pairs (_G ) do print (k, v) end
package 模块 package 模块是 Lua 中用于管理模块加载路径和模块搜索策略的核心模块。 通过 package 模块, 可以控制 Lua 如何查找和加载模块。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 print (package .config )print (package .path )package .path = package .path .. ";./?.lua;./lib/?.lua;./lib/?/init.lua" print (package .path )print (package .cpath )package .cpath = package .cpath .. ";./?.so" print (package .cpath )for i, searcher in ipairs (package .searchers) do print ("Searcher" , i, ":" , searcher) end for i, loader in ipairs (package .loaders ) do print ("Loader" , i, ":" , loader) end package .preload .myModule = function () return {name="My Module" } end local mod = require ('myModule' )print (mod .name) package .seeall (_G )mod = require ('myModule' )print (mod .name) local path = package .searchpath('myModule' , package .path )print (path ) local dlopen = package .loadlib ("libm.so" , "luaopen_m" )dlopen() print (math .pi )
coroutine 模块 coroutine 模块是 Lua 中用于支持协同程序( coroutine) 的功能模块。 协同程序是一种轻量级的线程, 可以在程序的不同部分之间切换执行。 通过 coroutine 模块, 可以在 Lua 中创建、 控制和管理协同程序。
coroutine.create 创建一个新的协同程序。 func 是一个 Lua 函数, 该函数将在新创建的协同程序中执行。
1 2 3 4 5 6 7 8 local co = coroutine .create (function () print ("Coroutine started" ) coroutine .yield () print ("Coroutine resumed" ) end )coroutine .resume (co) coroutine .resume (co)
coroutine.resume 恢复一个暂停的协同程序 co 的执行。 可以传递额外的参数给协同程序的 yield 方法。
1 2 3 4 5 6 7 local co = coroutine .create (function () local result, arg1, arg2 = coroutine .yield () print ("Received:" , result, arg1, arg2) end )coroutine .resume (co) coroutine .resume (co, "result" , "arg1" , "arg2" )
coroutine.running 返回当前正在运行的协同程序的句柄。 如果是主协同程序( 启动程序) , 则返回 nil。
1 2 3 4 5 6 7 local co = coroutine .create (function () print ("Running coroutine:" , coroutine .running ()) coroutine .yield () end )coroutine .resume (co) print ("Running main coroutine:" , coroutine .running ())
coroutine.status 返回一个字符串, 指示协同程序 co 的状态。 可能的状态包括 “running”、 “normal”、 “suspended”、 “dead”。
1 2 3 4 5 6 7 8 9 10 11 local co = coroutine .create (function () print ("Running coroutine:" , coroutine .status (co)) coroutine .yield () print ("Resumed coroutine:" , coroutine .status (co)) end )print ("Initial status:" , coroutine .status (co)) coroutine .resume (co) print ("Suspended status:" , coroutine .status (co)) coroutine .resume (co) print ("Final status:" , coroutine .status (co))
coroutine.wrap 返回一个新函数, 该函数每次调用时都会创建一个新的协同程序并执行 func。 这可以用来创建可重用的协同程序。
1 2 3 4 5 6 7 8 local wrappedFunc = coroutine .wrap (function () print ("Wrapped coroutine started" ) coroutine .yield () print ("Wrapped coroutine resumed" ) end )wrappedFunc() wrappedFunc()
coroutine.yield 暂停当前协同程序的执行, 并返回可选的参数。 这是协同程序之间传递控制的主要手段。
1 2 3 4 5 6 7 8 9 local co = coroutine .create (function () print ("Before yield" ) coroutine .yield ("Result from coroutine" ) print ("After yield" ) end )coroutine .resume (co) local status , result = coroutine .resume (co) print ("Result:" , result)
示例代码 💗💗 使用 coroutine 模块来创建、 控制和管理协同程序。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 local co = coroutine .create (function () print ("Coroutine started" ) coroutine .yield () print ("Coroutine resumed" ) end )coroutine .resume (co)coroutine .resume (co)print ("Running coroutine:" , coroutine .running ()) local wrappedFunc = coroutine .wrap (function () print ("Wrapped coroutine started" ) coroutine .yield () print ("Wrapped coroutine resumed" ) end )wrappedFunc() wrappedFunc() local co2 = coroutine .create (function () print ("Running coroutine:" , coroutine .status (co2)) coroutine .yield () print ("Resumed coroutine:" , coroutine .status (co2)) end )coroutine .resume (co2)print ("Suspended status:" , coroutine .status (co2)) coroutine .resume (co2)print ("Final status:" , coroutine .status (co2))
debug 模块 debug 模块是 Lua 中用于调试和追踪程序执行过程的重要工具。 它提供了多种方法来获取运行时的信息、 设置调试钩子、 调整环境等。
debug.getinfo 1 2 3 4 5 6 7 8 function testInfo () local info = debug .getinfo (1 , 1 , "Slnt" ) print (info.short_src, info.currentline) end testInfo()
debug.getregistry 1 2 3 4 local registry = debug .getregistry ()print (registry)
debug.setfenv 1 2 3 4 5 6 7 8 9 function testSetEnv () local env = {} debug .setfenv (1 , 1 , env) print (env) end testSetEnv()
debug.getfenv 1 2 3 4 5 6 7 8 function testEnv () local env = debug .getfenv (1 , 1 ) print (env) end testEnv()
debug.sethook 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function testSetHook () local count = 0 local hookFunc = function () count = count + 1 print ("Line" , count) end debug .sethook (1 , "l" , 0 , hookFunc) for i = 1 , 5 do print (i) end end testSetHook()
debug.gethook 1 2 3 4 5 6 7 8 function testHook () local hook = debug .gethook (1 , 1 ) print (hook) end testHook()
debug.setlocal 1 2 3 4 5 6 7 8 9 function testSetLocal () local a = 1 debug .setlocal (1 , 1 , "a" , 10 ) print (a) end testSetLocal()
debug.getlocal 1 2 3 4 5 6 7 8 9 10 function testLocal () local a = 1 local b = 2 local name, value = debug .getlocal (1 , 1 , 1 ) print (name, value) end testLocal()
1 2 3 4 5 6 local t = {}local mt = {}debug .setmetatable (t, mt)print (debug .getmetatable (t))
1 2 3 4 5 6 local t = {}local mt = {}setmetatable (t, mt)print (debug .getmetatable (t))
debug.setupvalue 1 2 3 4 5 6 7 8 9 10 11 12 13 14 local function outer () local x = 10 local inner = function () return x end return inner end local innerFunc = outer()local _, _ = debug .getupvalue (innerFunc, 1 )debug .setupvalue (innerFunc, 1 , 20 )print (innerFunc())
debug.getupvalue 1 2 3 4 5 6 7 8 9 10 11 12 13 local function outer () local x = 10 local inner = function () return x end return inner end local innerFunc = outer()local name, value = debug .getupvalue (innerFunc, 1 )print (name, value)
示例代码 💗💗 使用 debug 模块中的方法来获取和设置运行时的信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 function testInfo () local info = debug .getinfo (1 , 1 , "Slnt" ) print (info.short_src, info.currentline) end testInfo() function testLocal () local a = 1 local b = 2 local name, value = debug .getlocal (1 , 1 , 1 ) print (name, value) end testLocal() local t = {}local mt = {}setmetatable (t, mt)print (debug .getmetatable (t)) local registry = debug .getregistry ()print (registry) local function outer () local x = 10 local inner = function () return x end return inner end local innerFunc = outer()local name, value = debug .getupvalue (innerFunc, 1 )print (name, value) function testSetEnv () local env = {} debug .setfenv (1 , 1 , env) print (env) end testSetEnv() function testSetHook () local count = 0 local hookFunc = function () count = count + 1 print ("Line" , count) end debug .sethook (1 , "l" , 0 , hookFunc) for i = 1 , 5 do print (i) end end testSetHook() function testSetLocal () local a = 1 debug .setlocal (1 , 1 , "a" , 10 ) print (a) end testSetLocal() local t = {}local mt = {}debug .setmetatable (t, mt)print (debug .getmetatable (t)) local function outer () local x = 10 local inner = function () return x end return inner end local innerFunc = outer()local _, _ = debug .getupvalue (innerFunc, 1 )debug .setupvalue (innerFunc, 1 , 20 )print (innerFunc())
math 模块 math 模块是 Lua 中用于执行数学运算的标准库。 它提供了各种数学函数, 包括基本的数学运算、 指数和对数运算、 三角函数以及一些常量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 print (math .abs (-3 )) print (math .acos (0.5 )) print (math .asin (0.5 )) print (math .atan (1 )) print (math .atan2 (1 , 1 )) print (math .ceil (3.14 )) print (math .cos (math .pi / 2 )) print (math .cosh (1 )) print (math .deg (math .pi )) print (math .exp (1 )) print (math .floor (3.99 )) print (math .fmod (10 , 3 )) local mantissa, exponent = math .frexp (123.45 )print (mantissa, exponent) local result = math .ldexp (0.7715625 , 7 )print (result) print (math .log (math .exp (1 ))) print (math .log10 (100 )) print (math .max (1 , 2 , 3 , 4 , 5 )) print (math .min (1 , 2 , 3 , 4 , 5 )) local intPart, fracPart = math .modf (3.14 )print (intPart, fracPart) print (math .pow (2 , 3 )) print (math .rad (180 )) print (math .random ()) print (math .random (10 )) print (math .random (1 , 100 )) math .randomseed (os .time ())print (math .random ()) print (math .sin (math .pi / 2 )) print (math .sinh (1 )) print (math .sqrt (16 )) print (math .tan (math .pi / 4 )) print (math .tanh (1 )) print (math .huge ) print (math .pi )
string 模块 string 模块是 Lua 中用于处理字符串的标准库。 它提供了多种方法来创建、 比较、 分割、 拼接字符串以及其他常用的字符串操作功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 local str = "Hello, World!" print (string .len (str)) local str = "Hello, World!" print (string .byte (str, 1 )) print (string .byte (str, 7 , 8 )) local str = string .char (72 , 101 , 108 , 108 , 111 )print (str) local str = "abc" print (string .rep (str, 3 )) local str = "Hello, World!" local start, endPos = string .find (str, "World" )print (start, endPos) local str = "100 apples and 20 oranges" for num in string .gmatch (str, "%d+" ) do print (num) end local str = "Hello, World!" local newStr = string .gsub (str, "o" , "O" , 2 )print (newStr) local str = "Hello, World!" print (string .sub (str, 8 )) local str = "Hello, World!" print (string .reverse (str)) local str = "HELLO, WORLD!" print (string .lower (str)) local str = "hello, world!" print (string .upper (str)) local number = 10 print (string .format ("The number is %d" , number)) local packed = string .pack("ii" , 1 , 2 )print (packed) local size = string .packsize("ii" , 1 , 2 )print (size) local packed = string .pack("ii" , 1 , 2 )local a, b = string .unpack ("ii" , packed)print (a, b)
table 模块 table 模块是 Lua 中用于处理表格( tables) 的标准库。 表格是 Lua 中的一种数据结构, 它可以看作是关联数组, 能够存储任意类型的值, 并且可以用任意类型的值作为键。 table 模块提供了多种方法来创建、 排序、 遍历表格, 以及其他常用的操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 local t = {"Hello" , "World" , "!" }print (table .concat (t, ", " )) local t = {a=1 , b=2 , c=3 }table .foreach (t, function (k, v) print (k, v) end )local t = {"a" , "b" , "c" }table .foreachi (t, function (i, k, v) print (i, v) end )local t = {1 , 2 , 4 }table .insert (t, 3 ) print (table .concat (t, ", " )) table .insert (t, 2 , "new" ) print (table .concat (t, ", " )) local t = {1 , 2 , 3 }print (table .maxn (t)) local t = {1 , 2 , 3 , 4 }table .remove (t) print (table .concat (t, ", " )) table .remove (t, 2 ) print (table .concat (t, ", " )) local t = {3 , 1 , 2 }table .sort (t)print (table .concat (t, ", " )) local t = {{"b" , 2 }, {"a" , 1 }}table .sort (t, function (a, b) return a[1 ] < b[1 ] end )print (table .concat (table .move(t, 1 , #t, 1 , {}), ", " ))
os 模块 os 模块是 Lua 中用于与操作系统交互的标准库。 它提供了各种与系统时间、 环境变量、 文件执行等相关的函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 local now = os .time ()print (now) local dateString = os .date ("%Y-%m-%d %H:%M:%S" , now)print (dateString) local t1 = os .time ()local t2 = os .time ()local diff = os .difftime (t2, t1)print ("Difference: " .. diff .. " seconds" ) os .execute ("echo Hello, World!" ) local path = os .getenv ("PATH" )print (path ) local currentLocale = os .setlocale () print (currentLocale) os .setlocale ("C" ) local startTime = os .clock ()local endTime = os .clock ()local elapsed = endTime - startTimeprint ("Elapsed time: " .. elapsed .. " seconds" )
io 模块 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 local file = io .open ("example.txt" , "w" )file:write ("Hello, World!\n" ) file:close () file = io .open ("example.txt" , "r" ) local content = file:read ("*a" )print (content) for line in io .lines ("example.txt" ) do print (line) end local cmdOutput = io .popen ("ls" , "r" )for line in cmdOutput:lines () do print (line) end cmdOutput:close () local tempFile = io .tmpfile ()tempFile:write ("Temporary data\n" ) tempFile:close () print (io .read ()) print (io .read ("*n" )) print (io .read ("*a" )) io .write ("Hello, " , "World!" , "\n" )io .input (io .open ("input.txt" , "r" ))local inputLine = io .read ()print (inputLine)io .output (io .open ("output.txt" , "w" ))print ("Hello, World!" )io .close (file)io .flush ()
bit32 模块 bit32 模块是 Lua 5.2 及以上版本中用于位操作的标准库。 它提供了一系列用于处理整数位运算的功能, 如位移、 逻辑运算、 旋转等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 print (bit32.arshift(0 b1100, 2 )) print (bit32.arshift(0 b1100, -2 )) print (bit32.band(0 b1100, 0 b1010)) print (bit32.bnot(0 b1100)) print (bit32.bor(0 b1100, 0 b1010)) print (bit32.btest(0 b1100, 2 )) print (bit32.btest(0 b1100, 1 )) print (bit32.bxor(0 b1100, 0 b1010)) print (bit32.extract(0 b11001010, 2 , 3 )) print (bit32.extract(0 b11001010, 2 )) print (bit32.replace(0 b11001010, 0 b101, 2 , 3 )) print (bit32.replace(0 b11001010, 0 b101, 2 )) print (bit32.lrotate(0 b1100, 2 )) print (bit32.lrotate(0 b1100, -2 )) print (bit32.rrotate(0 b1100, 2 )) print (bit32.rrotate(0 b1100, -2 ))
utf8 模块 utf8 模块是 Lua 中用于处理 UTF-8 编码字符串的标准库。 UTF-8 是一种可变长度的字符编码方式, 它可以用来表示 Unicode 字符集中的任何字符。 utf8 模块提供了一些函数来帮助开发者处理这种编码的字符串。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 local str = utf8.char (0x68 , 0x65 , 0x6c , 0x6c , 0x6f ) print (str) local str2 = utf8.char (0x1f600 ) print (str2) local str = "😀你好" local codepoint = utf8.codepoint(str, 1 )print (codepoint) local str = "😀你好" local offset = utf8.offset(str, 1 )print (offset) local str = "😀你好" local length = utf8.len (str)print (length) local str = "😀你好世界" local subStr = utf8.sub (str, 2 , 4 )print (subStr)
LuaJIT LuaJIT( Lua Just-In-Time Compiler) 是一个高性能的Lua解释器, 它为Lua 5.1提供即时编译( JIT) 功能。 LuaJIT不仅提高了Lua代码的执行效率, 而且还增加了许多有用的特性, 如FFI( Foreign Function Interface) 和更高效的内存管理。
LuaJIT的特点
即时编译( JIT) : LuaJIT能够在运行时将热点代码( hot path) 编译成本地机器码, 从而显著提高执行效率。
内存管理: LuaJIT改进了垃圾回收机制, 减少了内存碎片和内存开销。
FFI支持: LuaJIT支持FFI, 可以直接调用C语言函数, 无需使用传统的Lua-C桥接。
多线程支持: LuaJIT支持多线程, 可以通过协程( coroutine) 实现并发执行。
向量化指令集: LuaJIT支持SSE/SSE2/SSE3/AVX指令集, 可以利用现代CPU的SIMD( 单指令多数据) 能力来加速计算密集型任务。
主要模块和功能
外部函数接口: ffi模块允许Lua代码直接操作C语言的数据类型和调用C语言的函数。 这使得Lua可以无缝集成C语言库, 无需编写额外的包装代码。
JIT编译: LuaJIT的JIT编译器会自动识别热点代码, 并将其编译成本地机器码。 这意味着对于频繁执行的代码片段, LuaJIT会在运行时对其进行优化。
内存管理: LuaJIT改进了垃圾回收机制, 减少了内存碎片和内存开销。 它使用了一种称为“ 增量标记-清除” 的垃圾回收算法, 可以在代码执行的同时进行垃圾回收。
协程支持: LuaJIT支持协程, 可以轻松实现非阻塞的并发执行。
向量化指令集: LuaJIT支持SSE/SSE2/SSE3/AVX指令集, 可以利用现代CPU的SIMD能力来加速计算密集型任务。
安装 LuaJIT 💗💗 在 Linux 上安装 LuaJIT 1 sudo apt-get install lua5.1 luajit
💗💗 在 macOS 上安装 LuaJIT
💗💗 在 Windows 上安装 LuaJIT 1 可以从官网下载预编译的二进制包, 或者使用 Chocolatey 等包管理工具
LuaJIT-FFI LuaJIT-FFI 是 LuaJIT( Just-In-Time Compiler for Lua) 的一个重要特性, 允许 Lua 脚本直接调用 C 语言编写的函数, 并支持在 Lua 中使用 C 数据类型。 ffi( Foreign Function Interface) 提供了与 C 语言交互的能力, 使得 Lua 可以更加高效地利用底层库的功能。
定义 C 类型和函数 1 2 3 4 5 ffi.cdef[[ typedef unsigned long uint32_t; void* malloc(size_t size); void free(void* ptr); ]]
加载 C 库 1 local libc = ffi.load ("c" )
创建 C 类型的实例 1 2 3 local intArray = ffi.new("int[10]" )intArray[0 ] = 42 print (intArray[0 ])
将一个值转换为指定的 C 类型 1 2 local intPtr = ffi.cast("int*" , 42 )print (intPtr[0 ])
将一个 C 字符串转换为 Lua 字符串 1 2 3 local cStr = ffi.new("char[]" , "Hello, world!" )local luaStr = ffi.string (cStr)print (luaStr)
设置一个垃圾收集器函数来释放 C 动态分配的内存 1 2 local cStr = ffi.new("char[100]" , "Hello, world!" )ffi.gc(cStr, ffi.C.free)
调用 C 函数 1 2 local sum = ffi.C.my_addition_function(10 , 20 )print (sum)
获取 C 类型的元信息 1 2 local intType = ffi.typeof("int" )print (intType.size)
获取结构体成员相对于结构体起始位置的偏移量 1 2 3 4 5 6 7 8 9 ffi.cdef[[ struct Person { char name[20]; int age; }; ]] local nameOffset = ffi.offsetof("struct Person" , "name" )print (nameOffset)
获取 C 类型的大小 1 2 local intSize = ffi.sizeof("int" )print (intSize)
获取 C 类型的名字 1 2 local intTypeName = ffi.C.typename(ffi.typeof("int" ))print (intTypeName)
示例代码 💗💗 使用 luajit-ffi 模块中的方法来进行 C 语言的函数调用和类型操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 ffi.cdef[[ typedef unsigned long uint32_t; // 定义一个简单的 C 函数 uint32_t add(uint32_t x, uint32_t y); // 定义一个结构体 struct Point { int x; int y; }; // 定义一个 C 函数来操作结构体 void setPoint(struct Point* point, int x, int y); ]] local libc = ffi.load ("c" )local addFunc = ffi.C.addlocal sum = addFunc(10 , 20 )print (sum) local point = ffi.new("struct Point" )ffi.C.setPoint(point, 100 , 200 ) print (point.x) print (point.y) local cStr = ffi.new("char[100]" , "Hello, world!" )local luaStr = ffi.string (cStr)print (luaStr) local mem = libc.malloc(100 )ffi.gc(mem, libc.free) local str = ffi.string (mem, 100 )str = "New string" ffi.C.memcpy(mem, ffi.string (str), #str) local intArray = ffi.new("int[10]" )intArray[0 ] = 42 print (intArray[0 ]) local intType = ffi.typeof("int" )print (intType.size) local xOffset = ffi.offsetof("struct Point" , "x" )print (xOffset)
Lua沙箱 在开发过程中, 尤其是在处理不可信的第三方代码或者用户提交的脚本时, 创建一个安全的执行环境是非常重要的。 Lua 沙箱( Sandboxing) 是一种技术, 它可以在一个受限的环境中执行Lua代码, 防止恶意代码对系统造成损害。 通过沙箱技术, 我们可以限制代码的执行范围, 防止其访问敏感资源, 如文件系统、 网络或其他系统资源。
💗💗 创建Lua沙箱有几种常见的方法, 包括但不限于:
限制全局环境: 通过修改全局环境来限制可用的API。
使用独立的Lua状态: 每个沙箱使用一个独立的Lua状态, 以防止不同沙箱之间的相互干扰。
使用LuaJIT的保护模式: 在LuaJIT中, 可以使用保护模式来限制某些操作。
限制全局环境 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 local env = {}setmetatable (env, { __index = _G })env.math = math env.table = table env.string = string env.error = error env.assert = assert setfenv (1 , env)local code = [[ print("Hello, sandbox!") io.open("secret.txt", "w"):write("This should not be written!") -- 尝试写入文件 ]] load (code)()
使用独立的Lua状态 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 local L = require 'lua' local state = L.newstate()L.pushcfunction(state, function () print ("Hello, isolated sandbox!" ) local f = L.Lloadbuffer(state, [[ print("This is a sandboxed environment.") io.open("secret.txt", "w"):write("This should not be written!") ]] ) if L.pcall (state, f, 0 , -2 ) ~= 0 then local msg = L.tostring (state, -1 ) print ("Error:" , msg) end end )L.call(state) L.close (state)
使用LuaJIT的保护模式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 local protect = require 'jit' .protectlocal protectedEnv = { nojit = true , nogc = true , nodebug = true } local env = setmetatable ({}, { __index = _G })env.math = math env.table = table env.string = string env.error = error env.assert = assert protect(env, protectedEnv) local code = [[ print("Hello, protected sandbox!") io.open("secret.txt", "w"):write("This should not be written!") -- 尝试写入文件 ]] load (code, nil , "t" , env)()
第三方库 安装第三方库 手动安装 对于一些简单的库, 可以通过手动下载源代码文件并将其放在你的项目目录中来使用。
下载源代码: 从官方 GitHub 仓库或其他源下载源代码。
放置文件: 将下载的文件放到项目的某个目录下, 例如 libs 文件夹。
加载库: 在 Lua 脚本中使用 require 加载库。
1 2 local example = require ('libs.example' )
使用 LuaRocks 安装 LuaRocks 类似于 Python 的 pip 或 Node.js 的 npm, 是一个用于安装 Lua 库的包管理工具。
安装 LuaRocks
1 2 3 4 5 6 7 8 sudo apt-get install luarocks brew install luarocks choco install luarocks
使用 LuaRocks 安装
1 2 luarocks install lua-socket
加载库
1 local socket = require ('socket' )
自动构建和安装 对于需要编译的库, 如 luaposix 或者某些 C/C++ 扩展库, 可能需要先编译源代码再安装。
下载源代码: 从官方仓库下载源代码。
配置编译: 根据库提供的 README 或 INSTALL 文件进行配置和编译。
安装库: 使用 make install 或者库提供的安装脚本进行安装。
1 2 3 4 git clone https://github.com/luaposix/luaposix.git cd luaposixmake sudo make install
容器化安装 如果你在一个容器化的环境中工作, 可以将 Lua 和所需的库打包到 Docker 镜像中。
1 2 3 4 FROM ubuntu:latest RUN apt-get update && apt-get install -y luarocks RUN luarocks install lua-socket CMD ["lua" , "your_script.lua" ]
LuaSocket 库 LuaSocket 是一个用于网络编程的库, 提供了处理 TCP/IP 和 UDP 协议的功能。 这个库使得在 Lua 中进行网络通信变得非常简单和直观。
socket.select 检测一组套接字的状态, 以确定哪些套接字准备好进行读取、 写入或出现异常。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 local select = require ('socket' ).select local rset = {socket.tcp(), socket.tcp()}local wset = {socket.tcp(), socket.tcp()}local eset = {}local readyRead, readyWrite, excepted = select (rset, wset, eset, 0 )if readyRead then for _, sock in ipairs (readyRead) do print (sock:receive("*a" )) end end if readyWrite then for _, sock in ipairs (readyWrite) do print (sock:send("data" )) end end if excepted then for _, sock in ipairs (excepted) do print ("Exception on socket:" , sock) end end
socket.bind 绑定一个地址和端口到一个新的套接字。
1 2 3 4 5 local bind = require ('socket' ).bindlocal server = bind("0.0.0.0" , 8080 , "inet" )server:listen(5 ) print ("Server bound to port 8080." )
socket.connect 连接到指定的主机和端口。
1 2 3 4 5 6 7 local connect = require ('socket' ).connectlocal client = connect("www.example.com" , 80 )client:send("GET / HTTP/1.0\r\nHost: www.example.com\r\n\r\n" ) local response = client:receive("*a" )print (response)client:close ()
socket.tcp 创建一个新的 TCP 套接字。
1 2 3 4 5 6 7 8 local tcp = require ('socket' ).tcplocal sock = tcp()sock:connect("www.example.com" , 80 ) sock:send("GET / HTTP/1.0\r\nHost: www.example.com\r\n\r\n" ) local response = sock:receive("*a" )print (response)sock:close ()
socket.udp 创建一个新的 UDP 套接字。
1 2 3 4 5 6 7 8 9 10 11 local udp = require ('socket' ).udplocal sock = udp()sock:setoption("reuseaddr" , "on" ) sock:bind("*" , 12345 ) local addr = sock:getpeername()print (addr.ip, addr.port)sock:sendto("Hello, UDP!" , "127.0.0.1" , 12345 ) local data, peer = sock:receivefrom(1024 )print (data, peer.ip, peer.port)sock:close ()
socket.listen 监听指定端口上的连接请求。
1 2 3 4 5 6 7 8 9 10 local listen = require ('socket' ).listenlocal server = listen(8080 )local client, addr = server:accept()print ("Connected by" , addr.ip, addr.port)local request = client:receive("*a" )print (request)client:send("HTTP/1.0 200 OK\r\n\r\nHello, World!" ) client:close () server:close ()
socket.gethostname 获取本地主机名。
1 2 3 local gethostname = require ('socket' ).gethostnameprint (gethostname())
socket.gethostbyname 获取主机的 IP 地址。
1 2 3 local gethostbyname = require ('socket' ).gethostbynameprint (gethostbyname("www.example.com" ))
socket.gethostbyaddr 获取 IP 地址对应的主机名。
1 2 3 local gethostbyaddr = require ('socket' ).gethostbyaddrprint (gethostbyaddr("127.0.0.1" ))
socket.getaddrinfo 获取一个或多个地址信息记录。
1 2 3 4 5 6 local getaddrinfo = require ('socket' ).getaddrinfolocal addresses = getaddrinfo("www.example.com" , "http" )for _, info in ipairs (addresses) do print (info.family, info.socktype, info.protocol, info.address, info.port) end
socket.resolve 解析主机名和端口号。
1 2 3 4 local resolve = require ('socket' ).resolvelocal ip, port = resolve("www.example.com" , "http" )print (ip, port)
socket.create 仅 LuaSocket 3.x, 创建一个套接字, 并设置其选项。
1 2 3 4 5 6 7 8 local create = require ('socket' ).create local sock = create ("inet" )sock:setoption("reuseaddr" , "on" ) sock:bind("*" , 12345 ) local addr = sock:getpeername()print (addr.ip, addr.port)sock:close ()
示例代码 💗💗 使用 LuaSocket 模块中的方法来进行网络通信 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 local socket = require ('socket' )local sock = socket.tcp()sock:connect("www.example.com" , 80 ) sock:send("GET / HTTP/1.0\r\nHost: www.example.com\r\n\r\n" ) local response = sock:receive("*a" )print (response)sock:close () local udpSock = socket.udp()udpSock:bind("*" , 12345 ) udpSock:sendto("Hello, UDP!" , "127.0.0.1" , 12345 ) local data, peer = udpSock:receivefrom(1024 )print (data, peer.ip, peer.port)udpSock:close () local server = socket.listen(8080 )local client, addr = server:accept()print ("Connected by" , addr.ip, addr.port)local request = client:receive("*a" )print (request)client:send("HTTP/1.0 200 OK\r\n\r\nHello, World!" ) client:close () server:close ()
LuaSec 库 LuaSec 是一个用于加密和安全相关的库, 提供了多种加密算法、 哈希函数、 随机数生成等功能。 它基于 OpenSSL 库, 因此可以在 Lua 中方便地使用高级加密功能。
随机数 1 2 3 4 5 6 7 8 9 local openssl = require ('openssl' )local randomBytes = openssl.rand(16 )print (randomBytes) local randomBytes = openssl.rand_pseudo_bytes(16 )print (randomBytes)
SHA-1 1 2 local hash = openssl.sha1("Hello, World!" )print (hash)
SHA-224 1 2 local hash = openssl.sha224("Hello, World!" )print (hash)
SHA-256 1 2 local hash = openssl.sha256("Hello, World!" )print (hash)
SHA-384 1 2 local hash = openssl.sha384("Hello, World!" )print (hash)
SHA-512 1 2 local hash = openssl.sha512("Hello, World!" )print (hash)
MD5 1 2 local hash = openssl.md5("Hello, World!" )print (hash)
HMAC 1 2 local hmac = openssl.hmac("sha256" , "secret-key" , "Hello, World!" )print (hmac)
Diffie-Hellman 1 2 3 4 5 6 7 8 9 10 11 12 local dh = openssl.dh_generate_parameters(1024 , function (err, dh) if not err then print (dh:export()) else print ("Error generating DH parameters:" , err) end end )local key = dh:generate_key()print (key:export())
AES 1 2 3 4 5 6 7 8 9 local key = openssl.rand(16 )local iv = openssl.rand(16 )local encrypted = openssl.aes_encrypt("Hello, World!" , key, iv)print (encrypted) local decrypted = openssl.aes_decrypt(encrypted, key, iv)print (decrypted)
PBKDF2 1 2 local key = openssl.pkcs5.pbkdf2("password" , "salt" , 1000 , 32 , "sha256" )print (key)
X.509 证书 1 2 3 4 5 6 7 8 9 10 11 12 local cert = openssl.x509.X509_new()local subject = openssl.x509.X509_Name_new()subject:add_entry_by_text("CN" , "example.com" , 0 ) openssl.x509.X509_set_subject_name(cert, subject) local key = openssl.crypto.PKey_new()key:gen_rsa(2048 ) openssl.x509.X509_set_pubkey(cert, key)
crypto 1 2 3 4 5 6 7 8 9 10 11 12 local key = openssl.crypto.PKey_new()key:gen_rsa(2048 ) print (key:export()) local exported = key:export(nil , "password" )print (exported) local imported = openssl.crypto.PKey_import(exported, "password" )print (imported)
LuaFileSystem 库 LuaFileSystem( 简称 LFS) 是一个用于处理文件系统的库, 提供了比 Lua 标准 io 模块更强大的文件和目录操作功能。
获取文件 1 2 3 4 5 6 7 8 9 local lfs = require ('lfs' )local attr = lfs.attributes("example.txt" )print (attr.size) print (attr.mode) print (attr.ctime) lfs.attributes("example.txt" , {atime = os .time ()})
更改权限 1 lfs.chmod("example.txt" , "rwxr-x---" )
更改所有者和组 1 lfs.chown("example.txt" , "user" , "group" )
复制文件 1 lfs.copy("source.txt" , "destination.txt" , true )
获取文件夹列表 1 2 3 4 5 local dir = lfs.dir("." )for entry in dir do print (entry) end dir.close ()
查找文件在路径列表中的位置 1 2 local path = lfs.find_path("example.txt" , {"./" , "./data/" })print (path or "File not found" )
查找目录在路径列表中的位置 1 2 local dir = lfs.find_dir("data" , {"./" , "./examples/" })print (dir or "Directory not found" )
创建目录 1 lfs.mkdir("new_directory" )
删除文件或目录 1 lfs.remove ("example.txt" )
重命名文件或目录 1 lfs.rename ("oldname.txt" , "newname.txt" )
同步文件描述符 1 2 3 4 local file = io .open ("example.txt" , "w" )file:write ("Some content" ) lfs.sync(file) file:close ()
创建符号链接 1 lfs.symlink("example.txt" , "example_link.txt" )
读取符号链接的目标 1 2 local target = lfs.readlink("example_link.txt" )print (target)
创建一个临时文件名 1 2 local tmpfile = lfs.tmpname ()print (tmpfile )
创建一个带有前缀和后缀的临时文件名 1 2 local tmpfile = lfs.tempname("tmp" , ".txt" )print (tmpfile )
设置文件的时间戳 1 lfs.settime("example.txt" , {mtime = os .time ()})
Luasql 库 luasql 是一个用于数据库访问的 Lua 库, 支持多种数据库驱动, 包括 MySQL、 PostgreSQL、 SQLite、 Oracle 等。 luasql 提供了一个统一的 API 来处理不同的数据库, 使得在 Lua 中进行数据库操作变得简单且一致。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 local luasql = require ('luasql.mysql' )local env = luasql.mysql()local db = env:connect('database_name' , 'username' , 'password' )local stmt = db:execute [[CREATE TABLE IF NOT EXISTS users (id INT PRIMARY KEY, name TEXT)]] stmt:close () local insertStmt = db:execute [[INSERT INTO users (id, name) VALUES (?, ?)]] insertStmt:bind(1 , "John Doe" ) insertStmt:execute () insertStmt:close () local queryStmt = db:execute [[SELECT * FROM users]] local row = queryStmt:fetch({dir = luasql.FETCH_ALL})while row do print ("ID:" , row.id, "Name:" , row.name) row = queryStmt:fetch({dir = luasql.FETCH_ALL}) end queryStmt:close () local updateStmt = db:execute [[UPDATE users SET name = ? WHERE id = ?]] updateStmt:bind("Jane Doe" ) updateStmt:bind(1 ) updateStmt:execute () updateStmt:close () local deleteStmt = db:execute [[DELETE FROM users WHERE id = ?]] deleteStmt:bind(1 ) deleteStmt:execute () deleteStmt:close () db:close () env:close ()
Luaposix 库 luaposix 是一个用于 Lua 的库, 它提供了 POSIX 系统调用的封装, 使得开发者可以直接在 Lua 中使用 POSIX API 进行系统级编程。 这包括文件操作、 进程管理、 信号处理等。
检查文件是否可访问 1 2 3 4 local posix = require ('posix' )local isReadable = posix.access("/etc/passwd" , "R_OK" )print (isReadable and "Readable" or "Not readable" )
改变当前工作目录
更改文件或目录的权限 1 posix.chmod("/tmp/test.txt" , "rw-r--r--" )
更改文件或目录的所有者和组 1 posix.chown("/tmp/test.txt" , "user" , "group" )
关闭文件描述符 1 2 local fd = posix.open ("/tmp/test.txt" , "O_RDWR" )posix.close (fd)
复制文件描述符 1 local new_fd = posix.dup(fd)
获取环境变量数组 1 2 3 4 local env = posix.environ()for k, v in pairs (env) do print (k .. "=" .. v) end
替换当前进程映像 1 posix.execl("/bin/ls" , "ls" , "-l" )
更改文件描述符指向的文件的权限 1 posix.fchmod(fd, "rw-r--r--" )
更改文件描述符指向的文件的所有者和组 1 posix.fchown(fd, "user" , "group" )
执行文件控制操作 1 2 3 local flags = posix.fcntl(fd, "F_GETFL" )local newFlags = flags | "O_APPEND" posix.fcntl(fd, "F_SETFL" , newFlags)
创建子进程 1 2 3 4 5 6 7 8 9 local pid = posix.fork()if pid == 0 then posix.execl("/bin/echo" , "echo" , "Hello from child" ) else local status = posix.waitpid(pid, 0 ) print ("Child exited with status:" , status ) end
获取文件描述符指向的文件的路径配置信息 1 2 local maxLinks = posix.fpathconf(fd, "PC_MAX_CANON" )print ("Maximum links:" , maxLinks)
截断文件描述符指向的文件至指定长度 1 posix.ftruncate(fd, 1024 )
获取当前工作目录 1 2 local cwd = posix.getcwd()print ("Current directory:" , cwd)
获取环境变量的值 1 2 local path = posix.getenv ("PATH" )print ("PATH:" , path )
获取用户的辅助组 ID 列表 1 2 3 4 local groups = posix.getgroups()for _, gid in ipairs (groups) do print ("Group ID:" , gid) end
获取当前登录用户名 1 2 local login = posix.getlogin()print ("Login:" , login)
获取当前进程的进程组 ID 1 2 local pgrp = posix.getpgrp()print ("Process Group ID:" , pgrp)
获取当前进程的进程 ID 1 2 local pid = posix.getpid()print ("Process ID:" , pid)
获取当前进程的父进程 ID 1 2 local ppid = posix.getppid()print ("Parent Process ID:" , ppid)
获取当前进程的有效用户 ID 1 2 local uid = posix.getuid()print ("User ID:" , uid)
检查文件描述符是否指向一个终端设备 1 2 local isTerm = posix.isatty(fd)print (isTerm and "Is terminal" or "Not terminal" )
发送信号给进程 1 posix.kill(pid, "SIGTERM" )
创建硬链接 1 posix.link("/tmp/test.txt" , "/tmp/test_link.txt" )
定位文件描述符的位置 1 posix.lseek(fd, 0 , "SEEK_SET" )
创建目录 1 posix.mkdir("/tmp/newdir" , "0755" )
创建 FIFO( 命名管道) 1 posix.mkfifo("/tmp/myfifo" , "0666" )
打开文件 1 local fd = posix.open ("/tmp/test.txt" , "O_RDWR|O_CREAT" , "0644" )
创建管道 1 2 local fds = {}posix.pipe(fds)
打开一个进程供读写 1 2 3 4 local pipe = posix.popen ("/bin/ls" , "r" )local output = pipe:read ("*a" )pipe:close () print (output )
从文件描述符读取数据 1 2 local data = posix.pread(fd, 1024 , 0 )print (data)
向文件描述符写入数据 1 posix.pwrite(fd, "Hello, world!" , 0 )
从文件描述符读取数据 1 2 local data = posix.read (fd, 1024 )print (data)
读取符号链接的目标 1 2 local target = posix.readlink("/tmp/symblink" )print (target)
删除空目录 1 posix.rmdir("/tmp/newdir" )
设置环境变量 1 posix.setenv("TEST_VAR" , "value" )
注册信号处理程序 1 2 3 posix.signal("SIGINT" , function (sig) print ("Caught signal:" , sig) end )
创建套接字 1 local sock = posix.socket("AF_INET" , "SOCK_STREAM" , "0" )
获取文件的状态信息 1 2 local st = posix.stat("/tmp/test.txt" )print ("Size:" , st.st_size)
创建符号链接 1 posix.symlink("/tmp/test.txt" , "/tmp/symblink" )
同步文件系统缓冲区
向文件描述符写入数据 1 posix.write (fd, "Hello, world!" )
等待子进程结束 1 2 local status = posix.waitpid(pid, 0 )print ("Child exited with status:" , status )
示例代码 💗💗 使用 luaposix 模块中的方法来进行系统级编程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 local posix = require ('posix' )posix.mkdir("/tmp/newdir" , "0755" ) local fd = posix.open ("/tmp/newdir/test.txt" , "O_RDWR|O_CREAT" , "0644" )posix.write (fd, "Hello, world!" ) posix.close (fd) posix.symlink("/tmp/newdir/test.txt" , "/tmp/newdir/symblink" ) local target = posix.readlink("/tmp/newdir/symblink" )print ("Symbolic link target:" , target)local st = posix.stat("/tmp/newdir/test.txt" )print ("File size:" , st.st_size)local pid = posix.fork()if pid == 0 then posix.execl("/bin/echo" , "echo" , "Hello from child" ) else local status = posix.waitpid(pid, 0 ) print ("Child exited with status:" , status ) end posix.setenv("TEST_VAR" , "value" ) local testVar = posix.getenv ("TEST_VAR" )print ("Environment variable TEST_VAR:" , testVar)posix.signal("SIGINT" , function (sig) print ("Caught signal:" , sig) end )posix.sync() posix.rmdir("/tmp/newdir" )
Lualanes 库 lualanes 是一个用于 Lua 的并发编程库, 它提供了一种轻量级的线程模型, 称为“ 协程车道” ( coroutine lanes) 。 lualanes 旨在解决 Lua 中的并发问题, 特别是在游戏开发中, 它可以帮助实现更复杂的并行任务管理。
创建车道 1 2 local lanes = require ('lanes' )local lane = lanes.new("MainLane" )
运行协程 1 2 3 lane:run(function (args) print ("Running task with args:" , args) end , "some data" )
挂起协程 1 2 3 4 5 lane:run(function () print ("Yielding..." ) lane:yield ("yield value" ) print ("Resumed after yield." ) end )
挂起当前协程 1 2 3 4 5 lane:run(function () print ("Suspending..." ) lane:suspend() print ("Resumed after suspend." ) end )
唤醒协程 1 2 3 4 5 6 7 lane:run(function () print ("Suspending..." ) lane:suspend() print ("This line won't be printed until wakeup." ) end )lane:wakeup("wakeup value" )
恢复协程 1 2 3 4 5 6 7 8 lane:run(function () print ("Yielding..." ) local res = lane:yield ("yield value" ) print ("Resumed after yield. Got:" , res) end )local result = lane:resume ("resume value" )print ("Resume result:" , result)
获取协程数量 1 print (lane:coroutines())
垃圾回收
杀死所有协程
示例代码 💗💗 使用 lualanes 模块中的方法来进行并发任务管理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 local lanes = require ('lanes' )local lane = lanes.new("ExampleLane" )lane:run(function () print ("Task started." ) print ("Yielding..." ) local res = lane:yield ("yield value" ) print ("Resumed after yield. Got:" , res) print ("Task finished." ) end )local resumeResult = lane:resume ("resume value" )print ("Resume result:" , resumeResult)lane:run(function () print ("Another task started." ) print ("Suspending..." ) lane:suspend() print ("This line won't be printed until wakeup." ) end )lane:wakeup("wakeup value" ) print ("Active coroutines:" , lane:coroutines())lane:garbage_collect() lane:kill()
love2d 库 Love2D 是一个轻量级的游戏开发框架, 用于编写2D游戏。 它支持多种平台, 包括Windows、 macOS、 Linux等, 并且使用Lua作为脚本语言。 Love2D 提供了一系列模块来处理图形、 音频、 输入等, 让开发者能够专注于游戏逻辑而不用担心底层细节。
主模块 主模块提供了游戏循环的主要入口点
💗💗 当游戏启动时调用一次, 用于初始化游戏资源 1 2 3 function love.load () print ("Game loaded." ) end
💗💗 每一帧调用一次, 用于更新游戏逻辑 1 2 3 function love.update (dt) print ("Updating game logic." ) end
💗💗 每一帧调用一次, 用于绘制游戏画面 1 2 3 function love.draw () love.graphics.print ("Hello, Love2D!" , 100 , 100 ) end
💗💗 当游戏退出时调用, 用于清理资源 1 2 3 function love.quit () print ("Cleaning up resources." ) end
文件模块 💗💗 返回保存目录的路径 1 print (love.filesystem.getSaveDirectory())
💗💗 检查文件是否存在 1 2 3 if love.filesystem.exists("example.txt" ) then print ("File exists." ) end
💗💗 向文件追加一行文本 1 love.filesystem.writeline("example.txt" , "Hello, Love2D!" )
图形模块 💗💗 清除屏幕颜色 1 love.graphics.clear(0.1 , 0.1 , 0.1 , 1 )
💗💗 设置当前颜色 1 love.graphics.setColor(1 , 0 , 0 , 1 )
💗💗 在屏幕上打印文本 1 love.graphics.print ("Hello, Love2D!" , 100 , 100 )
💗💗 绘制矩形 1 love.graphics.rectangle("fill" , 100 , 100 , 100 , 50 )
图像模块 💗💗 创建新的图像数据 1 local imgData = love.image.newImageData(100 , 100 )
💗💗 从数据创建图像数据 1 local imgData = love.image.newImageData(data, 100 , 100 , "rgba8" , false )
音频模块 💗💗 创建一个新的音源 1 local sound = love.sound.newSource("sound.wav" , "static" )
💗💗 播放音源
键盘模块 💗💗 检查按键是否按下 1 2 3 if love.keyboard.isDown("escape" ) then love.event.quit() end
鼠标模块 💗💗 检查鼠标按钮是否按下 1 2 3 if love.mouse.isDown("left" ) then print ("Left mouse button is down." ) end
💗💗 获取鼠标当前位置 1 2 local mouseX, mouseY = love.mouse.getPosition()print (mouseX, mouseY)
窗口模块 💗💗 设置窗口标题 1 love.window.setTitle("My Game" )
💗💗 设置窗口模式 1 love.window.setMode(800 , 600 , {fullscreen=false })
物理模块 💗💗 创建新的刚体 1 local body = love.physics.newBody(world, 100 , 100 , "dynamic" )
💗💗 创建新的形状 1 local shape = love.physics.newShape(body, "rectangle" , 0 , 0 , 10 , 10 )
定时器模块 💗💗 获取当前时间 1 print (love.timer.getTime())
💗💗 获取上一帧的时间差 1 print (love.timer.getDelta())
示例代码 💗💗 使用 Love2D 模块中的方法来进行基本的游戏开发 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 function love.load () love.window.setTitle("Hello, Love2D!" ) love.window.setMode(800 , 600 , {fullscreen=false }) love.graphics.setBackgroundColor(0.1 , 0.1 , 0.1 , 1 ) end function love.update (dt) if love.keyboard.isDown("escape" ) then love.event.quit() end end function love.draw () love.graphics.setColor(1 , 0 , 0 , 1 ) love.graphics.print ("Hello, Love2D!" , 100 , 100 ) love.graphics.rectangle("fill" , 100 , 100 , 100 , 50 ) end function love.quit () print ("Game has quit." ) end
设计模式 单例模式 单例模式确保一个类只有一个实例, 并提供一个全局访问点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 local Singleton = {}Singleton.__instance = nil function Singleton.getInstance () if Singleton.__instance == nil then Singleton.__instance = {} setmetatable (Singleton.__instance, Singleton) end return Singleton.__instance end function Singleton:doSomething () print ("Doing something..." ) end local singletonInstance = Singleton.getInstance()singletonInstance:doSomething()
工厂模式 工厂模式提供了一个创建对象的接口, 但允许子类决定实例化哪一个类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 local Factory = {}function Factory:createObject (objectType) if objectType == "ConcreteObjectA" then return setmetatable ({name = "ConcreteObjectA" }, ConcreteObjectA) elseif objectType == "ConcreteObjectB" then return setmetatable ({name = "ConcreteObjectB" }, ConcreteObjectB) else error ("Invalid object type" ) end end local ConcreteObjectA = {}function ConcreteObjectA:getName () return self .name end local ConcreteObjectB = {}function ConcreteObjectB:getName () return self .name end local objectA = Factory.createObject("ConcreteObjectA" )print (objectA:getName())
观察者模式 观察者模式定义了对象间的一种一对多依赖关系, 当一个对象的状态发生改变时, 所有依赖它的对象都会得到通知并自动更新。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 local Subject = {}Subject.observers = {} function Subject:addObserver (observer) table .insert (self .observers, observer) end function Subject:removeObserver (observer) for i, ob in ipairs (self .observers) do if ob == observer then table .remove (self .observers, i) end end end function Subject:notifyObservers () for _, observer in ipairs (self .observers) do observer:update(self ) end end local Observer = {}function Observer:update (subject) print ("Observer notified by subject: " .. tostring (subject)) end local subject = {}setmetatable (subject, Subject)local observer = {}setmetatable (observer, Observer)subject:addObserver(observer) subject:notifyObservers()
学习资源