一篇博客学习Lua_安装使用+语法详解

发布于:2025-07-13 ⋅ 阅读:(14) ⋅ 点赞:(0)

1. Lua 概述


1.1 Lua简介

​ Lua 是一种由标准 C 语言开发的开源、可扩展的轻量级脚本语言。它最初于 1993 年 由巴西里约热内卢天主教大学的三位研究人员开发,主要用于嵌入式系统和游戏开发。Lua 的设计目标是 简单性灵活性,使其能够轻松集成到其他应用程序中。

核心特点

  • 轻量级:Lua 的核心库非常小,适合资源受限的环境。
  • 动态类型:变量无需声明类型,类型在运行时自动推断。
  • 弱类型:支持隐式类型转换。
  • 解释型:通过 Lua 解释器直接执行脚本,无需编译。
  • 可扩展性:通过 C/C++ 扩展功能,支持自定义模块。
  • 跨平台:支持 Linux、Windows、macOS 等主流操作系统。
  • 广泛用途:常用于游戏开发(如 Roblox)、Web 服务器(如 OpenResty)、嵌入式系统等。

Lua 官网

Lua 的官方网站为 https://www.lua.org/,提供源码、文档和社区支持。


1.2 Linux 系统的 Lua

1.2.1 Lua 下载与安装

在 Linux 系统中使用 Lua,需从官网下载源码并编译安装。以下是详细步骤:

  1. 下载源码
    从官网下载最新版本的 Lua 源码包(如 lua-5.4.8.tar.gz)。

  2. 解压源码
    将源码包上传到 Linux 服务器,并解压到指定目录(如 /opt/apps/lua):

    tar -zxvf lua-5.4.8.tar.gz -C /opt/apps/
    
  3. 安装 GCC 编译器
    Lua 是用 C/C++ 编写的,需要 GCC 编译器支持:

    sudo apt-get install build-essential
    
  4. 编译与安装
    进入解压后的 Lua 目录,执行编译命令:

    make linux test
    

    编译完成后,安装 Lua:

    sudo make install
    
  5. 验证安装
    通过以下命令验证 Lua 是否安装成功:

    lua -v
    

    输出结果应包含 Lua 版本号(如 Lua 5.4.8)。

1.2.2 输出Hello World

Lua 提供了两种交互模式:命令行模式脚本文件模式

A. 命令行模式

直接在终端输入 Lua 命令即可运行:

lua

进入 Lua 命令行后,输入以下代码:

print("Hello, World!")

按回车键,输出结果为:

Hello, World!

输入 Ctrl+C 退出命令行模式。

B. 脚本文件模式

  1. 创建一个 Lua 脚本文件(如 hello.lua):

    print("Hello, World!")
    
  2. 运行脚本文件:

    lua hello.lua
    
  3. 可执行文件方式
    修改脚本文件为可执行文件:

    • 在脚本文件顶部添加解释器路径:
      #!/usr/bin/lua
      print("Hello, World!")
      
    • 赋予脚本可执行权限:
      chmod +x hello.lua
      
    • 直接运行脚本:
      ./hello.lua
      

1.3 Windows 系统的 Lua

在 Windows 系统中,最常用的 Lua 环境是 SciTE,它是一个集成了 Lua 编辑器和运行环境的工具。

安装 SciTE

  1. 下载地址
    SciTE 的官方下载地址为 https://github.com/rjpcomputing/luaforwindows/releases

  2. 安装步骤

    • 下载安装包(如 LuaForWindows-5.3.5.20170929.exe)。
    • 双击安装包,按照提示完成安装。
    • 安装完成后,SciTE 会自动配置 Lua 环境变量。

运行 Lua 脚本

  1. 命令行运行
    在 SciTE 中编写脚本后,点击菜单栏的 Run > Run,或按下 F5 键运行脚本。

  2. 调试功能
    SciTE 支持断点调试、变量查看等功能,适合初学者学习 Lua 语法。

其他工具

  • LuaDist:一个 Lua 包管理工具,简化依赖管理。
  • LuaRocks:Lua 的包管理器,类似 Python 的 pip,可安装第三方库。

2. Lua 语法


2.1 Lua 语法基础

2.1.1 注释

Lua 的注释分为两种形式:

  • 行注释:以 -- 开头,注释一行内容:

    -- 这是一个行注释
    print("Hello")  -- 注释可以跟在代码后
    
  • 段注释:以 --[[ 开始,以 --]] 结束,支持多行注释:

    --[[ 
    这是一个段注释
    可以跨越多行
    --]]
    print("Hello")
    

技巧:如果需要临时取消段注释,可在开头添加一个 -,使注释失效:

---[[
print("Hello")  -- 此行不会被注释
--]]

2.1.2 数据类型

Lua 有 8 种基础数据类型,通过 type() 函数可查询数据类型:

数据类型 描述
nil 表示无效值,与 false 类似,但不等同。
boolean 布尔类型,值为 truefalse
number 双精度浮点数类型,支持整数和小数。
string 字符串类型,支持单引号和双引号,可跨行。
table Lua 的唯一复合数据结构,类似于数组或字典。
function 函数类型,支持匿名函数。
thread 协程(协同线程),用于实现并发。
userdata 用户自定义数据类型,通常通过 C/C++ 扩展使用。

示例

print(type(nil))        --> nil
print(type(true))       --> boolean
print(type(123))        --> number
print(type("Hello"))    --> string
print(type({}))         --> table
print(type(function() end)) --> function

2.1.3 标识符

​ 程序设计语言中的标识符主要包含保留字、变量、常量、方法名、函数名、类名等。Lua 的标识符由字母、数字与下划线组成,但不能以数字开头。Lua 是大小写敏感的。

(1)保留字

​ Lua 常见的保留字共有 22 个。不过,除了这 22 个外,Lua 中还定义了很多的内置全局变量,这些内置全局变量的一个共同特征是,以下划线开头后跟全大写字母。所以我们在定义自己的标识符时不能与这些保留字、内置全局变量重复。

and break do else
elseif end false for
function if in local
nil not or repeat
return then true until
while goto

(2)变量

​ Lua 是弱类型语言,变量无需类型声明即可直接使用。变量分为全局变量与局部变量。Lua 中的变量默认都是全局变量,即使声明在语句块或函数里。全局变量一旦声明,在当前文件中的任何地方都可访问。局部变量 local 相当于 Java 中的 private 变量,只能在声明的语句块中使用。

(3)动态类型

Lua 是动态类型语言,变量的类型可以随时改变,无需声明。


2.1.4 运算符

Lua 支持多种运算符,包括算术运算符、关系运算符、逻辑运算符等。

A. 算术运算符

运算符 描述 示例
+ 加法 a + b
- 减法 a - b
* 乘法 a * b
/ 除法 5 / 2 → 2.5
% 取余 10 % 3 → 1
^ 乘方 2^3 → 8
// 整除(Lua 5.3+) 5 // 2 → 2

注意

  • // 仅在 Lua 5.3 及以上版本可用。
  • SciTE 默认支持 Lua 5.1,需升级环境才能使用新特性。

B. 关系运算符

运算符 描述 示例
== 等于 a == b
~= 不等于 a ~= b
> 大于 a > b
< 小于 a < b
>= 大于等于 a >= b
<= 小于等于 a <= b

布尔逻辑

  • Lua 将 falsenil 视为假,其他值(包括 0 和空字符串)视为真。

C. 逻辑运算符

运算符 描述 示例
and 逻辑与 a and b
or 逻辑或 a or b
not 逻辑非 not a

短路特性

  • and:若第一个操作数为假,直接返回第一个操作数。
  • or:若第一个操作数为真,直接返回第一个操作数。

D. 其他运算符

运算符 描述 示例
.. 字符串连接 "Hello" .. "World" → “HelloWorld”
# 获取长度(字符串或表) #"Hello" → 5

2.1.5 函数

Lua 的函数定义以 function 关键字开始,以 end 结束。

A. 固定参数函数

function add(a, b)
    return a + b
end
print(add(1, 2))  --> 3

特点

  • 参数数量可变,不足时用 nil 补足,超出部分忽略。

B. 可变参数函数

使用 ... 表示可变参数:

function sum(...)
    local args = {...}
    local total = 0
    for i, v in ipairs(args) do
        total = total + v
    end
    return total
end
print(sum(1, 2, 3))  --> 6

C. 返回多个值

Lua 函数可返回多个值:

function getValues()
    return 1, 2, 3
end
local a, b, c = getValues()
print(a, b, c)  --> 1 2 3

D. 函数作为参数

Lua 支持将函数作为参数传递:

function apply(func, a, b)
    return func(a, b)
end
print(apply(function(x, y) return x + y end, 1, 2))  --> 3

2.1.6 流程控制语句

A. if 条件判断

Lua 的 if 语句语法简洁:

if condition then
    -- 条件成立时执行
elseif condition2 then
    -- 第二个条件成立时执行
else
    -- 所有条件都不成立时执行
end

示例

local x = 10
if x > 5 then
    print("x is greater than 5")
else
    print("x is less than or equal to 5")
end

B. if 嵌套

if 语句支持嵌套:

if x > 5 then
    if x < 10 then
        print("x is between 5 and 10")
    end
end

2.1.7 循环控制语句

A. while 循环

local i = 1
while i <= 3 do
    print(i)
    i = i + 1
end

B. repeat-until 循环

while 不同,repeat-until 会先执行循环体,再判断条件:

local i = 1
repeat
    print(i)
    i = i + 1
until i > 3

C. 数值 for 循环

适用于固定范围的循环:

for i = 1, 3 do
    print(i)
end

参数说明

  • i:循环变量。
  • 1:起始值。
  • 3:结束值。
  • 可选步长:for i = 1, 10, 2 do ... end(步长为 2),默认步长为1。

D. 泛型 for 循环

用于遍历 table,需配合迭代器使用:

local t = {1, 2, 3}
for index, value in ipairs(t) do
    print(index, value)
end

E. break 语句

用于提前终止循环:

for i = 1, 10 do
    if i == 5 then
        break
    end
    print(i)
end

F. goto 语句

Lua 支持 goto 跳转,但需谨慎使用:

::label::
print("Hello")
goto label  -- 无限循环

注意

  • Lua 5.1 不支持 ::label:: 语法,需升级到 5.3+。

2.2 Lua语法进阶

2.2.1 table

核心概念

table 是 Lua 中唯一的数据结构,既可以表示数组(列表),也可以表示键值对(类似字典/Map),甚至可以混合使用。

1. 数组

  • 特点

    • 索引从 1 开始(默认)。
    • 可动态扩展,无需声明长度。
    • 支持任意类型元素(包括混合类型)。
  • 示例

    local arr = {10, "Lua", true}  
    print(arr[1])  -- 输出10  
    

2. Map(键值对)

  • 定义方式
    • 直接指定键值对:
      local map = {name = "张三", age = 23}  
      
    • 动态赋值:
      local map = {}  
      map["depart"] = "销售部"  
      
  • 访问方式
    • 通过键直接访问:map.keymap[key]
    • 数组索引方式访问(若键为数字)。

3. 混合结构

  • 特点
    • 数组索引(数字键)和普通键(字符串或其他)可共存。
    • 数组索引不会被普通键占用。
  • 示例
    local mixed = {10, 20, name = "混合表"}  
    print(mixed[1])     -- 输出10  
    print(mixed.name)   -- 输出"混合表"  
    

4. table操作函数

函数 功能 版本限制
table.concat(table, [sep, start, end]) 连接数组元素为字符串 所有版本
table.unpack(table, [i, j]) 拆包(返回数组元素) Lua5.3+
table.pack(...) 打包(参数转为table) Lua5.3+
table.maxn(table) 返回最大索引值 所有版本
table.insert(table, [pos, value]) 插入元素到指定位置 所有版本
table.remove(table, [pos]) 删除并返回指定位置的元素 所有版本
table.sort(table, [fun(a,b)]) 排序(升序或自定义规则) 所有版本

示例

local t = {10, 20, 30}  
print(table.concat(t, "-"))  -- 输出"10-20-30"  
table.insert(t, 40)  
table.sort(t)  
for i, v in ipairs(t) do print(v) end  

2.2.2 迭代器

核心概念

迭代器用于遍历 table 的元素。Lua 提供两种内置迭代器:ipairspairs

1. ipairs

  • 功能:仅遍历数组部分(数字索引,且元素非 nil)。
  • 适用场景:顺序遍历数组元素。
  • 示例
    local t = {10, 20, 30}  
    for i, v in ipairs(t) do  
        print(i, v)  -- 输出1 10, 2 20, 3 30  
    end  
    

2. pairs

  • 功能:遍历整个 table(包括数组和键值对)。
  • 适用场景:需要访问所有键值对时。
  • 示例
    local t = {10, 20, name = "Lua"}  
    for k, v in pairs(t) do  
        print(k, v)  -- 输出1 10, 2 20, name Lua  
    end  
    

3. 自定义迭代器

  • 原理:通过闭包实现状态维护。
  • 示例
    function my_iterator(t)  
        local i = 0  
        return function()  
            i = i + 1  
            return t[i]  
        end  
    end  
    
    local t = {10, 20, 30}  
    for v in my_iterator(t) do  
        print(v)  -- 输出10, 20, 30  
    end  
    

2.2.3 模块

核心概念

模块是 Lua 中用于组织和复用代码的机制,类似于其他语言的类库或命名空间。

1. 定义模块

  • 文件结构
    • 模块文件通常是一个 .lua 文件,返回一个 table
    • 表中包含模块的函数和变量。
  • 示例(文件 mymodule.lua):
    local M = {}  
    
    function M.add(a, b)  
        return a + b  
    end  
    
    return M  
    

2. 使用模块

  • 导入方式
    • 使用 require("模块路径") 导入,可省略小括号,无需 .lua 扩展名。
  • 示例
    local mymodule = require("mymodule")  
    print(mymodule.add(1, 2))  -- 输出3  
    

3. 模块注意事项

  • 全局变量污染:模块文件中定义的非 table 变量会成为全局变量。
  • 路径问题require 会从 LUA_PATH 环境变量指定的路径搜索模块。

2.2.4 元表与元方法

​ 元表(Metatable)是 Lua 中用于自定义表行为的核心机制。通过元表,开发者可以扩展表的操作逻辑,例如重载运算符、定义默认行为(如访问不存在的键)或实现自定义的函数调用方式。


1. 重要函数

1.1 setmetatable(table, metatable)

  • 功能:将 metatable 指定为普通表 table 的元表。

  • 示例

    local t = {10, 20}  
    local mt = {__add = function(a, b) return a.x + b.x end}  
    setmetatable(t, mt)  
    

1.2 getmetatable(table)

  • 功能:获取指定普通表 table 的元表。

  • 示例

    local mt = getmetatable(t)  
    print(mt)  -- 输出元表内容  
    

2. 核心元方法

2.1 __index 元方法

  • 触发条件:当访问表中不存在的键时触发。

  • 功能

    • 可以是一个函数:返回自定义值。
    • 可以是另一个表:从该表中查找键。
  • 示例

    -- 返回自定义值的情况  
    local mt = {  
      __index = function(tab, key)  
        return "未知的键: " .. key  
      end  
    }  
    
    local t = {x = 10}  
    setmetatable(t, mt)  
    print(t.y)  -- 输出 "未知的键: y"  
    
    -- 从另一个表中查找键的情况  
    local mt = {  
      __index = {y = 20}  
    }  
    local t = {x = 10}  
    setmetatable(t, mt)  
    print(t.y)  -- 输出 20  
    

2.2 __newindex 元方法

  • 触发条件:当向表中不存在的键赋值时触发。
  • 功能
    • 可以是一个函数:控制赋值逻辑。
    • 可以是另一个表:将键值对存储到该表中。
  • 示例
    -- 控制赋值逻辑  
    local mt = {  
      __newindex = function(tab, key, value)  
        print("新增键:", key, "值:", value)  
        rawset(tab, key, value)  -- 手动赋值  
      end  
    }  
    
    local t = {x = 10}  
    setmetatable(t, mt)  
    t.y = 20  -- 输出 "新增键: y 值: 20"  
    
    -- 将键值对存储到另一个表中  
    local mt = {  
      __newindex = {y = 30}  
    }  
    local t = {x = 10}  
    setmetatable(t, mt)  
    t.y = 20  -- 存储到 mt.__newindex 表中  
    print(t.y)  -- 输出 nil(因为未修改原始表)  
    print(mt.__newindex.y)  -- 输出 20  
    

3. 运算符元方法

通过重写运算符元方法,可以自定义表的运算行为。

3.1 常见运算符元方法

元方法 运算符 功能说明
__add + 加法操作
__sub - 减法操作
__mul * 乘法操作
__div / 除法操作
__mod % 取模操作
__pow ^ 幂运算
__unm - 取反操作
__eq == 相等性比较
__lt < 小于比较
__le <= 小于等于比较
__concat .. 字符串连接
__len # 获取表长度
__tostring tostring 自定义字符串表示
__call () 将表作为函数调用

3.2 示例:自定义加法运算

local mt = {  
  __add = function(a, b)  
    return a.x + b.x  
  end  
}  

local t1 = {x = 10}  
local t2 = {x = 20}  
setmetatable(t1, mt)  
print(t1 + t2)  -- 输出 30  

4. __tostring 元方法

直接输出一个table,其输出内容为类型为table的存放地址,如果想让其输出table中的内容,可重写__tostring方法。

  • 功能:自定义表的字符串表示。
  • 示例
    local mt = {  
      __tostring = function(t)  
        local str = "{ "  
        for k, v in pairs(t) do  
          str = str .. k .. "=" .. v .. ", "  
        end  
        return str .. "}"  
      end  
    }  
    
    local t = {x = 10, y = 20}  
    setmetatable(t, mt)  
    print(t)  -- 输出 { x=10, y=20, }  
    

5. __call 元方法

  • 功能:将表作为函数调用。
  • 示例
    local mt = {  
      __call = function(t, num, str)  
        for k, v in pairs(t) do  
          if type(v) == "number" then  
            t[k] = v + num  
          elseif type(v) == "string" then  
            t[k] = v .. str  
          end  
        end  
        return t  
      end  
    }  
    
    local t = {x = 10, y = "Hello"}  
    setmetatable(t, mt)  
    local newT = t(5, "-world")  
    for k, v in pairs(newT) do  
      print(k, v)  -- 输出 x=15, y=Hello-world  
    end  
    

6. 元表的高级应用

6.1 模拟类继承

通过 __index 实现类似类继承的逻辑:

-- 父类  
local Parent = {x = 10}  

-- 子类  
local Child = {y = 20}  

-- 设置子类的元表,指向父类  
setmetatable(Child, {__index = Parent})  

print(Child.x)  -- 输出 10(继承自 Parent)  
print(Child.y)  -- 输出 20  

6.2 自定义错误提示

当访问不存在的键时,返回自定义错误信息:

local mt = {  
  __index = function(t, key)  
    error("键 " .. key .. " 不存在")  
  end  
}  

local t = {x = 10}  
setmetatable(t, mt)  
print(t.y)  -- 抛出错误:键 y 不存在  

7. 元表的单独定义

为了便于复用,可以将元表定义为单独的模块文件。

7.1 定义元表文件(my_metatable.lua

local mt = {}  

mt.__index = function(t, key)  
  return "默认值: " .. key  
end  

return mt  

7.2 使用元表文件

local mt = require("my_metatable")  
local t = {x = 10}  
setmetatable(t, mt)  
print(t.y)  -- 输出 "默认值: y"  

总结

​ 元表是 Lua 中实现自定义行为的强大工具。通过合理使用 __index__newindex、运算符元方法等,可以扩展表的功能,实现类继承、自定义操作符甚至更复杂的逻辑。掌握元表的使用,能够显著提升 Lua 代码的灵活性和可维护性。


2.3 Lua模拟面向对象

Lua 中没有显式的类(class)概念,但通过 tablefunction 和元表(metatable)可以模拟类的功能。


2.3.1 简单对象的创建

通过 tablefunction 可以创建一个简单的对象。

定义对象

  • 属性:通过 table 的键值对存储。
  • 行为:通过 function 赋予对象的方法。

示例代码

-- 创建一个简单对象  
local person = {  
  name = "张三",  
  age = 22,  
  sayHello = function(self)  
    print("你好,我是" .. self.name)  
  end  
}  

person:sayHello()  -- 输出"你好,我是张三"  

2.3.2 类的创建

通过 tablefunction 和元表可以定义类,并支持继承。

1 定义基础类

  • new() 方法:用于创建类的实例。
  • 元表:通过 __index 实现继承。

示例代码

-- 定义基础类 Person  
local Person = {}  

function Person:new(name, age)  
  local obj = {name = name, age = age}  
  setmetatable(obj, {__index = self})  -- 设置元表,实现继承  
  return obj  
end  

function Person:sayHello()  
  print("你好,我是" .. self.name)  
end  

-- 创建对象  
local p1 = Person:new("张三", 23)  
p1:sayHello()  -- 输出"你好,我是张三"  

2 类的继承

通过元表的 __index 实现子类继承父类的属性和方法。

示例代码

-- 定义子类 Student 继承自 Person  
local Student = {}  
Student.__index = Student  

-- 设置 Student 的元表为 Person  
setmetatable(Student, {__index = Person})  

function Student:new(name, age, studentId)  
  local obj = Person:new(name, age)  -- 调用父类构造函数  
  obj.studentId = studentId  
  setmetatable(obj, self)  -- 设置元表  
  return obj  
end  

function Student:study()  
  print(self.name .. "正在学习")  
end  

-- 创建 Student 对象  
local s1 = Student:new("李四", 20, "S001")  
s1:sayHello()  -- 输出"你好,我是李四"  
s1:study()     -- 输出"李四正在学习"  

2.3.3 静态方法与私有变量

通过闭包和模块化设计可以实现静态方法和私有变量。

1 静态方法

  • 定义方式:直接定义在类表中,不依赖实例。

示例代码

-- 定义静态方法  
Person.getDescription = function()  
  return "这是一个Person类"  
end  

print(Person.getDescription())  -- 输出"这是一个Person类"  

2 私有变量

  • 实现方式:通过闭包保护变量,仅允许类内部访问。

示例代码

-- 使用闭包实现私有变量  
local Person = {}  
local privateData = {}  -- 私有变量  

function Person:new(name)  
  local obj = {name = name}  
  privateData[obj] = {secret = "这是私有数据"}  -- 存储私有数据  
  setmetatable(obj, self)  
  self.__index = self  
  return obj  
end  

function Person:getSecret()  
  return privateData[self].secret  -- 访问私有数据  
end  

local p1 = Person:new("王五")  
print(p1:getSecret())  -- 输出"这是私有数据"  
-- print(privateData.p1.secret)  -- 报错,无法直接访问私有数据  

2.3.4 多继承

通过元表的 __index 可以实现多继承(继承多个类的属性和方法)。

示例代码

-- 定义类 A  
local A = {}  
function A:sayA()  
  print("这是类A的方法")  
end  

-- 定义类 B  
local B = {}  
function B:sayB()  
  print("这是类B的方法")  
end  

-- 定义类 C,继承 A 和 B  
local C = {}  
setmetatable(C, {__index = A})  -- 继承 A  
C.__index = C  

function C:new()  
  local obj = {}  
  setmetatable(obj, self)  
  return obj  
end  

-- 将 B 的方法复制到 C 中(模拟多继承)  
for k, v in pairs(B) do  
  C[k] = v  
end  

local c = C:new()  
c:sayA()  -- 输出"这是类A的方法"  
c:sayB()  -- 输出"这是类B的方法"  

2.4 协同线程与协同函数

协同线程(coroutine)是 Lua 中的一种轻量级线程,允许程序在运行过程中暂停和恢复。


2.4.1 协同线程的基本操作

1 创建协同线程

  • coroutine.create(f):创建一个协同线程实例。

示例代码

local co = coroutine.create(function()  
  print("协同线程开始")  
end)  

2 启动协同线程

  • coroutine.resume(co):启动或恢复协同线程的执行。

示例代码

coroutine.resume(co)  -- 输出"协同线程开始"  

3 挂起协同线程

  • coroutine.yield():暂停当前协同线程的执行。

示例代码

local co = coroutine.create(function()  
  print("第一段")  
  coroutine.yield()  -- 挂起  
  print("第二段")  
end)  

coroutine.resume(co)  -- 输出"第一段"  
coroutine.resume(co)  -- 输出"第二段"  

4 查看协同线程状态

  • coroutine.status(co):返回协同线程的状态(runningsuspendeddead)。

示例代码

print(coroutine.status(co))  -- 输出"dead"  

5 关闭协同线程

  • coroutine.close(co):强制关闭协同线程。

示例代码

coroutine.close(co)  

2.4.2 协同函数

通过 coroutine.wrap(f) 可以创建协同函数,其调用会启动一个协同线程。

示例代码

local coFunc = coroutine.wrap(function()  
  print("协同函数开始")  
  coroutine.yield()  
  print("协同函数结束")  
end)  

coFunc()  -- 输出"协同函数开始"  
coFunc()  -- 输出"协同函数结束"  

2.4.3 协同线程的应用场景

1 生成器模式

协同线程可以作为生成器,逐次返回数据。

示例代码

function generator()  
  for i = 1, 3 do  
    coroutine.yield(i * 10)  
  end  
end  

local co = coroutine.create(generator)  
coroutine.resume(co)  
while true do  
  local status, value = coroutine.resume(co)  
  if not status then break end  
  print(value)  -- 依次输出10, 20, 30  
end  

2 状态机

协同线程可以用于实现状态机,逐步执行不同状态逻辑。

示例代码

local stateMachine = coroutine.create(function()  
  print("状态1")  
  coroutine.yield()  
  print("状态2")  
  coroutine.yield()  
  print("状态3")  
end)  

coroutine.resume(stateMachine)  -- 输出"状态1"  
coroutine.resume(stateMachine)  -- 输出"状态2"  
coroutine.resume(stateMachine)  -- 输出"状态3"  

2.5 文件 IO

Lua 提供了丰富的文件 IO 操作函数,分为静态函数和实例函数。


2.5.1 静态函数

1 io.open(filename, mode)

  • 功能:打开文件并返回文件句柄。
  • 模式说明
    • r:只读(默认)。
    • w:只写(覆盖原有内容)。
    • a:追加写入。
    • +:与 rwa 结合使用,表示读写模式。
    • b:二进制模式。

示例代码

local file = io.open("example.txt", "w")  
file:write("Hello, Lua!\n")  
file:close()  

2 io.input(file)

  • 功能:设置默认输入文件。

示例代码

io.input("example.txt")  
local content = io.read("*a")  -- 读取整个文件内容  
print(content)  -- 输出"Hello, Lua!"  

3 io.output(file)

  • 功能:设置默认输出文件。

示例代码

io.output("output.txt")  
io.write("写入内容\n")  
io.close()  

2.5.2 实例函数

1 file:read([format])

  • 功能:从文件中读取数据。
  • 格式说明
    • *l:读取一行(默认)。
    • *n:读取一个数字。
    • *a:读取整个文件。
    • number:读取指定字符数。

示例代码

local file = io.open("example.txt", "r")  
local line1 = file:read("*l")  -- 读取第一行  
local line2 = file:read("*l")  -- 读取第二行  
file:close()  
print(line1, line2)  

2 file:write(data)

  • 功能:将数据写入文件。

示例代码

local file = io.open("example.txt", "a")  
file:write("追加内容\n")  
file:close()  

3 file:seek([whence, offset])

  • 功能:设置或获取文件指针位置。
  • 参数说明
    • set:定位到文件开头(默认)。
    • cur:相对于当前位置。
    • end:定位到文件末尾。

示例代码

local file = io.open("example.txt", "r+")  
file:seek("set", 0)  -- 定位到文件开头  
file:write("新内容")  
file:close()  

文件操作的完整示例示例代码:

-- 写入文件  
local file = io.open("data.txt", "w")  
file:write("第一行\n")  
file:write("第二行\n")  
file:close()  

-- 读取文件  
file = io.open("data.txt", "r")  
print("读取文件内容:")  
for line in file:lines() do  
  print(line)  -- 依次输出"第一行"、"第二行"  
end  
file:close()  

暂时结束。


网站公告

今日签到

点亮在社区的每一天
去签到