Lua 详细教程

Lua 是一种轻量级、高效、可嵌入的脚本语言,广泛用于游戏开发、嵌入式系统和各种应用程序的扩展。以下是 Lua 的全面教程:

1. Lua 简介

主要特点

  • 轻量级:核心解释器仅约 200KB
  • 高效:执行速度快,内存占用低
  • 可嵌入:易于集成到 C/C++ 程序中
  • 动态类型:变量无需声明类型
  • 自动内存管理:垃圾回收机制
  • 多范式:支持过程式、面向对象和函数式编程

应用领域

  • 游戏开发(如魔兽世界、愤怒的小鸟)
  • 嵌入式系统
  • 应用程序扩展
  • 网络编程
  • 科学计算

2. Lua 安装

Linux 安装

# Ubuntu/Debian
sudo apt-get install lua5.3

# CentOS/RHEL
sudo yum install lua

# 从源码安装
wget http://www.lua.org/ftp/lua-5.4.3.tar.gz
tar -zxvf lua-5.4.3.tar.gz
cd lua-5.4.3
make linux test
sudo make install

Mac 安装

brew install lua

Windows 安装

  1. 从官网下载二进制包:https://www.lua.org/download.html
  2. 解压并添加到 PATH 环境变量

验证安装

lua -v

3. Lua 基础语法

Hello World

lua

print("Hello, World!")

注释

lua

-- 单行注释

--[[
 多行
 注释
]]

变量

lua

-- 全局变量(默认)
a = 10

-- 局部变量
local b = 20

-- 变量命名规则
-- 字母、数字、下划线,不以数字开头
var_name = "value"
_var2 = 123

4. 数据类型

基本类型

lua

print(type("Hello"))    --> string
print(type(10.4*3))     --> number
print(type(print)))     --> function
print(type(type)))      --> function
print(type(true)))      --> boolean
print(type(nil)))       --> nil
print(type(type(X))))   --> string

1. nil

lua

-- 表示无效值或空
local a
print(a)  --> nil

2. boolean

lua

-- 只有 true 和 false 两个值
local isAlive = true
local isDead = false

3. number

lua

-- 所有数字都是双精度浮点数
local num = 123
local pi = 3.14159
local hex = 0x1A
local sci = 2e10

4. string

lua

-- 单引号或双引号
local str1 = "hello"
local str2 = 'world'

-- 多行字符串
local multi = [[
第一行
第二行
]]

-- 字符串连接
print("hello " .. "world")  --> hello world

-- 字符串长度
print(#"hello")  --> 5

5. table

lua

-- Lua 唯一的复合数据结构
local t = {}  -- 空表

-- 数组形式
local arr = {10, 20, 30}
print(arr[1])  --> 10 (Lua 索引从1开始)

-- 字典形式
local dict = {name="Lua", version="5.4"}
print(dict["name"])  --> Lua
print(dict.name)     --> Lua

-- 混合形式
local mix = {
  "apple", 
  "banana",
  price = 10.5,
  [5] = "index 5"
}

6. function

lua

-- 函数是一等公民
local function add(a, b)
  return a + b
end

-- 匿名函数
local sub = function(a, b)
  return a - b
end

-- 函数作为参数
local function apply(func, a, b)
  return func(a, b)
end

print(apply(add, 5, 3))  --> 8

7. userdata 和 thread

lua

-- userdata 用于表示 C 数据结构
-- thread 表示协程

5. 运算符

算术运算符

lua

print(10 + 20)  --> 30
print(20 - 10)  --> 10
print(10 * 20)  --> 200
print(20 / 10)  --> 2.0
print(20 % 3)   --> 2
print(2 ^ 3)    --> 8

关系运算符

lua

print(10 == 10)  --> true
print(10 ~= 20)  --> true
print(10 < 20)   --> true
print(10 > 20)   --> false
print(10 <= 20)  --> true
print(10 >= 20)  --> false

逻辑运算符

lua

print(true and false)  --> false
print(true or false)   --> true
print(not true)        --> false

-- 短路求值
local a = 10
local b = 20
print(a > 0 and b > 0)  --> true

其他运算符

lua

-- 字符串连接
print("hello" .. " " .. "world")  --> hello world

-- 长度运算符
print(#{1, 2, 3})  --> 3

6. 控制结构

if 语句

lua

local age = 18

if age < 18 then
  print("未成年")
elseif age >= 18 and age < 60 then
  print("成年人")
else
  print("老年人")
end

while 循环

lua

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

repeat-until 循环

lua

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

for 循环

lua

-- 数值 for
for i = 1, 5 do
  print(i)
end

-- 带步长
for i = 10, 1, -1 do
  print(i)
end

-- 泛型 for (遍历表)
local t = {a=1, b=2, c=3}
for k, v in pairs(t) do
  print(k, v)
end

-- 遍历数组
local arr = {"a", "b", "c"}
for i, v in ipairs(arr) do
  print(i, v)
end

7. 函数

定义函数

lua

-- 基本形式
function greet(name)
  return "Hello, " .. name
end

-- 局部函数
local function add(a, b)
  return a + b
end

-- 匿名函数
local mul = function(a, b)
  return a * b
end

多返回值

lua

function swap(a, b)
  return b, a
end

x, y = swap(10, 20)
print(x, y)  --> 20 10

可变参数

lua

function sum(...)
  local s = 0
  for _, v in ipairs({...}) do
    s = s + v
  end
  return s
end

print(sum(1, 2, 3, 4))  --> 10

尾调用优化

lua

function foo(n)
  if n > 0 then
    return foo(n - 1)
  end
  return 0
end

8. 表(Table)

表的基本操作

lua

-- 创建表
local t = {}

-- 添加元素
t[1] = "first"
t["key"] = "value"
t.x = 10

-- 访问元素
print(t[1])      --> first
print(t["key"])  --> value
print(t.key)     --> value
print(t.x)       --> 10

-- 删除元素
t[1] = nil

表的方法

lua

local fruits = {"apple", "banana", "orange"}

-- 插入元素
table.insert(fruits, "pear")          -- 末尾插入
table.insert(fruits, 2, "grape")      -- 指定位置插入

-- 移除元素
table.remove(fruits)                  -- 移除最后一个
table.remove(fruits, 2)               -- 移除指定位置元素

-- 排序
table.sort(fruits)

-- 连接
print(table.concat(fruits, ", "))     --> apple, banana, grape, orange

元表(Metatable)

lua

local t1 = {10, 20, 30}
local t2 = {40, 50, 60}

-- 设置元表
local mt = {
  __add = function(a, b)
    local result = {}
    for i = 1, #a do
      table.insert(result, a[i] + b[i])
    end
    return result
  end
}

setmetatable(t1, mt)
setmetatable(t2, mt)

local t3 = t1 + t2
print(table.concat(t3, ", "))  --> 50, 70, 90

常用元方法

lua

__index    -- 访问不存在的键时调用
__newindex -- 给不存在的键赋值时调用
__add      -- +
__sub      -- -
__mul      -- *
__div      -- /
__mod      -- %
__pow      -- ^
__concat   -- ..
__eq       -- ==
__lt       -- <
__le       -- <=
__call     -- 把表当函数调用时
__tostring -- 转换为字符串时

9. 模块与包

创建模块

lua

-- mymodule.lua
local M = {}  -- 模块表

function M.add(a, b)
  return a + b
end

function M.sub(a, b)
  return a - b
end

return M

使用模块

lua

local mymodule = require("mymodule")

print(mymodule.add(10, 5))  --> 15
print(mymodule.sub(10, 5))  --> 5

包管理(LuaRocks)

# 安装 LuaRocks
sudo apt-get install luarocks

# 安装包
luarocks install luasocket

# 搜索包
luarocks search json

10. 协程(Coroutine)

基本使用

lua

-- 创建协程
local co = coroutine.create(function()
  print("协程开始")
  coroutine.yield()
  print("协程恢复")
end)

-- 运行协程
coroutine.resume(co)  --> 协程开始

-- 恢复协程
coroutine.resume(co)  --> 协程恢复

协程状态

lua

print(coroutine.status(co))  --> suspended/running/dead

数据交换

lua

local co = coroutine.create(function(a, b)
  coroutine.yield(a + b, a - b)
  return a * b
end)

print(coroutine.resume(co, 10, 5))  --> true 15 5
print(coroutine.resume(co))         --> true 50

11. 文件 I/O

简单模式

lua

-- 读取文件
local file = io.open("test.txt", "r")
local content = file:read("*a")
file:close()

-- 写入文件
local file = io.open("output.txt", "w")
file:write("Hello, Lua!")
file:close()

完全模式

lua

local file = assert(io.open("test.txt", "r"))

-- 逐行读取
for line in file:lines() do
  print(line)
end

file:close()

12. 错误处理

pcall

lua

local status, err = pcall(function()
  error("出错了!")
end)

if not status then
  print("错误:", err)  --> 错误: test.lua:2: 出错了!
end

xpcall

lua

local function errorHandler(err)
  print("错误处理:", err)
end

local status = xpcall(
  function()
    error("出错了!")
  end,
  errorHandler
)

13. 标准库

字符串库

lua

local s = "Hello, Lua!"

-- 大小写转换
print(string.upper(s))  --> HELLO, LUA!
print(string.lower(s))  --> hello, lua!

-- 查找
print(string.find(s, "Lua"))  --> 8 10

-- 截取
print(string.sub(s, 1, 5))    --> Hello

-- 格式化
print(string.format("PI = %.2f", math.pi))  --> PI = 3.14

-- 匹配模式
for word in string.gmatch(s, "%a+") do
  print(word)  --> Hello Lua
end

数学库

lua

print(math.sin(math.pi/2))  --> 1.0
print(math.floor(3.7))      --> 3
print(math.ceil(3.2))       --> 4
print(math.random(1, 100))  --> 随机数
print(math.max(10, 20))     --> 20

表库

lua

local t = {"a", "b", "c"}

-- 插入
table.insert(t, "d")

-- 移除
table.remove(t)

-- 排序
table.sort(t)

-- 连接
print(table.concat(t, ", "))  --> a, b, c

操作系统库

lua

print(os.time())       --> 当前时间戳
print(os.date("%Y-%m-%d"))  --> 2023-01-01
os.execute("ls")       --> 执行系统命令

14. 与 C 交互

从 Lua 调用 C 函数

// mylib.c
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

static int l_add(lua_State *L) {
  int a = luaL_checkinteger(L, 1);
  int b = luaL_checkinteger(L, 2);
  lua_pushinteger(L, a + b);
  return 1;
}

static const struct luaL_Reg mylib[] = {
  {"add", l_add},
  {NULL, NULL}
};

int luaopen_mylib(lua_State *L) {
  luaL_newlib(L, mylib);
  return 1;
}

编译为共享库:

gcc -shared -fPIC -o mylib.so mylib.c -I/usr/local/include -L/usr/local/lib -llua

Lua 中使用:

lua

local mylib = require("mylib")
print(mylib.add(10, 20))  --> 30

从 C 调用 Lua

// main.c
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

int main() {
  lua_State *L = luaL_newstate();
  luaL_openlibs(L);

  if (luaL_dofile(L, "script.lua")) {
    printf("Error: %s\n", lua_tostring(L, -1));
  }

  lua_close(L);
  return 0;
}

15. 最佳实践

代码风格

lua

-- 使用小写和下划线命名
local player_name = "John"

-- 常量使用大写
local MAX_SPEED = 100

-- 函数命名使用动词
function get_player_score(player_id)
  -- ...
end

-- 缩进使用2个空格
if condition then
  do_something()
end

性能优化

  1. 尽量使用局部变量
  2. 避免频繁创建和销毁表
  3. 使用 table.concat 连接大量字符串
  4. 预分配数组大小
  5. 避免不必要的垃圾回收

调试技巧

lua

-- 打印调试信息
print("Debug:", variable)

-- 使用 assert 检查条件
assert(type(var) == "number", "var should be a number")

-- 使用 debug 库
local info = debug.getinfo(1)
print("Current function:", info.name)

16. 实战示例

1. 简单计算器

lua

function calculate()
  print("请输入第一个数字:")
  local a = tonumber(io.read())

  print("请输入运算符(+, -, *, /):")
  local op = io.read()

  print("请输入第二个数字:")
  local b = tonumber(io.read())

  local result
  if op == "+" then
    result = a + b
  elseif op == "-" then
    result = a - b
  elseif op == "*" then
    result = a * b
  elseif op == "/" then
    result = a / b
  else
    print("无效运算符")
    return
  end

  print(string.format("结果: %.2f", result))
end

calculate()

2. 猜数字游戏

lua

math.randomseed(os.time())
local secret = math.random(1, 100)
local guess, attempts = 0, 0

print("猜数字游戏(1-100)")

while guess ~= secret do
  print("请输入你的猜测:")
  guess = tonumber(io.read())
  attempts = attempts + 1

  if guess < secret then
    print("太小了!")
  elseif guess > secret then
    print("太大了!")
  else
    print(string.format("恭喜! 你用了 %d 次猜对了!", attempts))
  end
end

3. 简单面向对象

lua

-- 定义类
local Person = {}

function Person:new(name, age)
  local obj = {
    name = name,
    age = age
  }
  setmetatable(obj, self)
  self.__index = self
  return obj
end

function Person:introduce()
  print(string.format("我叫 %s,今年 %d 岁", self.name, self.age))
end

-- 创建对象
local p = Person:new("张三", 25)
p:introduce()

Lua 是一门简洁而强大的语言,本教程涵盖了 Lua 的主要特性和用法。要精通 Lua 需要不断实践,建议通过实际项目来加深理解。









results matching ""

    No results matching ""