Lua语法速查笔记:table+元表核心机制与实战案例

本文详细介绍了Lua语言的核心语法,包括table和元表机制、数据类型、运算符、流程控制、函数、字符串操作、数组、迭代器、模块、协同程序、文件I/O、错误处理、面向对象等。适合Lua初学者和开发者快速查阅。

Lua 最特别的地方:table + 元表 统一了所有数据结构,数组、字典、对象、模块全用这一套。

一、概述

Lua 是巴西 PUC-Rio 大学在 1993 年搞出来的轻量级脚本语言,用标准 C 写,编译完才一百多 K。设计目标是嵌入应用程序里做扩展

主要使用场景:游戏开发(魔兽世界、愤怒的小鸟)、Web 应用脚本(OpenResty/Nginx)、数据库插件(Redis、MySQL Proxy)、安全工具。

核心特点

  • 轻量、可嵌入 C/C++ 宿主程序
  • 自动内存管理(增量标记-扫描 GC)
  • table 一把梭 —— 数组、哈希表、集合、对象全用它模拟
  • 函数是一等公民,支持闭包、匿名函数
  • 协同程序(coroutine),非抢占式多任务

二、第一个程序 & 运行方式

-- hello.lua
print("Hello, Lua!")

运行:

lua hello.lua         # 脚本式
lua -i                # 交互式,直接敲代码

或者加 Shebang:

#!/usr/local/bin/lua
print("Hello World!")
chmod +x hello.lua
./hello.lua

安装(Linux):

# 源码编译
curl -L -R -O https://www.lua.org/ftp/lua-5.4.7.tar.gz
tar zxf lua-5.4.7.tar.gz && cd lua-5.4.7
make all test && make install

# 包管理器
sudo apt install lua5.3        # Debian/Ubuntu
brew install lua                # macOS

三、基本语法

3.1 注释

-- 单行注释

--[[
  多行注释
  多行注释
]]

-- 注意:Lua 不支持嵌套注释,--[[ 里面再写 --[[ ]] 会出错

3.2 标识符 & 关键字

标识符规则:字母/下划线开头,后跟字母、下划线、数字,且区分大小写。

保留关键字(22 个):

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

注意:下划线加大写字母(如 _VERSION)被 Lua 内部保留,别用。

3.3 变量 & 赋值

Lua 的变量默认全是全局的,除非用 local 声明。访问不存在的变量不会报错,返回 nil。

a = 5            -- 全局变量
local b = 10     -- 局部变量(推荐!更快、更安全)

function test()
    c = 3        -- 没加 local,默认全局
    local d = 7  -- 局部,函数外不可见
end
test()
print(c, d)      --> 3   nil

删除变量:赋值为 nil。

b = nil
print(b)         --> nil  (等同于不存在)

多重赋值

a, b = 10, 20
a, b = b, a           -- 交换,不需要临时变量!

-- 数量不匹配时:
a, b, c = 0, 1        -- c 补 nil
a, b = 1, 2, 3        -- 多余的 3 被丢弃
a, b, c = 0           -- 0, nil, nil(常见错误,不会自动补0)

-- 函数多返回值直接接住
x, y = some_func()

3.4 作用域

local a = 5         -- 从声明处到所在块结束

do
    local b = 10    -- 仅在 do...end 块内可见
    print(b)        -- 10
end
-- print(b)         -- nil

两条建议

  1. 能用 local 尽量用,访问局部变量比全局快不少
  2. 避免命名冲突

四、数据类型

Lua 是动态类型,变量不声明类型。一共 8 种:

类型说明
nil空值/无效值,条件判断中等价于 false
booleantrue和 false
number双精度浮点(double),没有 int/float 之分
string字符串,单引号、双引号或 [[ ]]表示
function函数是一等公民
userdataC 语言传入的任意数据结构
thread协同程序(coroutine)
table万能容器:数组 + 哈希表 + 对象 + 模块
print(type("Hello"))      --> string
print(type(10.4 * 3))     --> number
print(type(print))        --> function
print(type(true))         --> boolean
print(type(nil))          --> nil
print(type(type))         --> function

4.1 nil

-- 未初始化的变量值就是 nil
print(a)      --> nil

-- 删除全局变量 / table 字段
a = nil

-- 注意:type 返回的是字符串 "nil",不是 nil
print(type(a) == nil)        --> false
print(type(a) == "nil")      --> true

4.2 boolean

Lua 判假只有两个值:false 和 nil。其他所有值全是 true,包括 0 和空字符串 ""!

if 0 then
    print("0 是 true")        -- 会执行!
end

if not nil then
    print("nil 是 false")     -- 会执行
end

4.3 number

只有一种数值类型,等价于 C 的 double。

print(type(2))
print(type(2.2))
print(type(2e+1))            -- 科学计数法
print(type(0.2e-1))
--> 全是 number

-- 算术运算时,字符串数字会自动转成数字
print("2" + 6)               --> 8.0
print("2" + "6")             --> 8.0
print("2 + 6")               --> "2 + 6"(只是字符串)
print("error" + 1)           --> 报错!不能转换

4.4 string

三种写法:单引号、双引号、[[ ]](长字符串,可含换行)。

s1 = 'hello'
s2 = "world"
s3 = [[
<html>
<body>多行文本可以不转义</body>
</html>
]]

-- 字符串连接用 ..(不是 +)
print("Hello " .. "World")   --> Hello World
print(157 .. 428)            --> "157428"(自动转成字符串)

-- 取长度用 #
print(#"abcde")              --> 5

转义字符与 C 基本一致:\n、\t、\\、\"等。

五、运算符

5.1 算术运算符

运算符说明示例
+-*/加减乘除3/2 → 1.5
%取余7%3 → 1
^幂运算(右结合)2^3^2 → 2^(3^2) = 512
-一元负号-x
//整除(Lua 5.3+)5//2 → 2

5.2 关系运算符

>、<、>=、<=、== 和 ~=。

注意:不等于是 ~=,不是 !=。

5.3 逻辑运算符

a and b       -- a 为假返回 a,否则返回 b
a or b        -- a 为真返回 a,否则返回 b
not a         -- 取反

-- 常用于默认值设置
x = x or 100           -- 如果 x 是 nil/false,用默认 100
name = name or "匿名"

5.4 其他运算符

"a" .. "b"         -- 字符串连接
#"hello"           -- 取长度(字符串或表的数组部分长度)

5.5 优先级

从高到低:

优先级运算符说明结合性
13

^

幂运算右结合
12

-、#

一元负号、取长度右结合
11

*、/、//、%

乘、除、整除、取模左结合
10

+、-

加、减左结合
9

..

字符串拼接右结合
8

<、>、<=、>=、~=、==

比较运算左结合
7

not

逻辑非(一元)右结合
6

and

逻辑与左结合
5

or

逻辑或左结合
1

=

赋值右结合

注意:括号 () 优先级最高,可以强制改变运算顺序。

六、流程控制

6.1 条件判断

-- if 格式(注意 then 和 end 关键字)
if (a < 20) then
    print("a 小于 20")
end

-- if...else
if (a < 20) then
    print("a < 20")
else
    print("a >= 20")
end

-- if...elseif...else
if (a == 10) then
    print("a = 10")
elseif (a == 20) then
    print("a = 20")
elseif (a == 30) then
    print("a = 30")
else
    print("没有匹配")
end

Lua 没有 switch,多分支用 if-elseif。

6.2 循环

三种循环结构:

-- 1. while:条件为真时重复
while (a < 10) do
    a = a + 1
end

-- 2. for(数值型):知道循环次数时用
for i = 1, 10 do          -- 从1到10
    print(i)
end
for i = 1, 10, 2 do       -- 步长为2
    print(i)
end

-- 3. repeat...until:至少执行一次,直到条件为真
repeat
    a = a + 1
until (a > 10)

6.3 控制语句

  • break:跳出当前循环(Lua 没有 continue,用 goto 代替)
  • goto:跳转到标签
-- goto 模拟 continue
for i = 1, 3 do
    if i <= 2 then
        print(i, "yes continue")
        goto continue
    end
    print(i, "no continue")
    ::continue::
    print("i'm end")
end

-- 标签定义
::label::
goto label

七、函数

7.1 定义 & 调用

-- 语法:[scope] function name(args)
--          body
--          return values
--        end

function max(a, b)
    if a > b then
        return a
    else
        return b
    end
end

local result = max(10, 4)   --> 10

7.2 多返回值

function max_and_index(t)
    local max_val = t[1]
    local max_idx = 1
    for i, v in ipairs(t) do
        if v > max_val then
            max_val, max_idx = v, i
        end
    end
    return max_val, max_idx    -- 返回两个值
end

val, idx = max_and_index({3, 9, 5, 2})   -- val=9, idx=2

7.3 可变参数

function add(...)
    local sum = 0
    local args = {...}             -- 将所有参数打包成 table
    for i, v in ipairs(args) do
        sum = sum + v
    end
    return sum
end

print(add(3, 4, 5, 6, 7))         --> 25

-- select("#", ...) 获取参数个数
function average(...)
    local sum = 0
    for i, v in ipairs({...}) do sum = sum + v end
    return sum / select("#", ...)
end

7.4 匿名函数 & 函数作参数

-- 匿名函数赋给变量
fact = function (n)
    if n == 0 then return 1
    else return n * fact(n - 1) end
end

-- 函数作为参数传递
function testFun(tab, fun)
    for k, v in pairs(tab) do
        print(fun(k, v))
    end
end

testFun({key1="a", key2="b"}, function(key, val)
    return key .. "=" .. val
end)

八、字符串操作

8.1 常用函数

函数说明示例
string.len(s)长度string.len("abc")3
string.upper(s)转大写"Lua""LUA"
string.lower(s)转小写"Lua""lua"
string.reverse(s)反转"Lua""auL"
string.sub(s, i, j)截取(从 1 开始)sub("12345",2,4)"234"
string.rep(s, n)重复 n 次rep("ab",2)"abab"
string.char(...)ASCII → 字符char(65,66)"AB"
string.byte(s, i)字符 → ASCIIbyte("ABC",1)65
string.format(...)格式化(类似 C printf)format("%.2f", 3.1415)"3.14"
string.find(s, pat)查找,返回首尾位置find("hello","ll")3, 4
string.gsub(s,pat,rep)替换gsub("aaaa","a","z",2)"zzaa"
string.match(s, pat)匹配第一个结果
string.gmatch(s, pat)返回匹配迭代器用于 for 循环
-- 字符串截取
local s = "prefix--runoobgoogletaobao--suffix"
print(string.sub(s, 4, 15))     --> fix--runoobg
print(string.sub(s, -10))       --> ao--suffix(后10个)

-- 格式化
string.format("%05d", 17)       --> "00017"
string.format("%.4f", 1/3)      --> "0.3333"
string.format("%q", "One\nTwo") --> '"One\nTwo"'

8.2 模式匹配

Lua 的"正则"是自己的模式匹配系统,比 PCRE 简单但够用。

-- 提取日期
s = "Deadline is 30/05/1999, firm"
pattern = "%d%d/%d%d/%d%d%d%d"
print(string.sub(s, string.find(s, pattern)))    --> 30/05/1999

常用字符类:

匹配
.任意字符
%a字母
%d数字
%s空白符
%w字母/数字
%l / %u小写/大写字母
%p标点符号
%c控制字符
%x十六进制数字

大写表示取反:%D= 非数字,%S= 非空白。

-- 匹配 email
for word in string.gmatch("a@x.com b@y.org", "%w+@%w+%.%w+") do
    print(word)
end

修饰符:*(0或多个,贪心)、+(1或多个)、-(0或多个,非贪心)、?(0或1个)。

捕获用 (),捕获内容可在 gsub 里用 %1%2引用。

九、数组

Lua 没有专门的数组类型,数组就是用 table 模拟的。索引默认从 1 开始(和大部分语言不一样!)。

-- 创建
local arr = {10, 20, 30, 40, 50}
print(arr[1])        --> 10
print(arr[3])        --> 30
print(#arr)           --> 5(长度)

-- 遍历
for i = 1, #arr do
    print(arr[i])
end

-- 末尾追加
arr[#arr + 1] = 60

-- table 库操作
table.insert(arr, 3, 25)    -- 在位置 3 插入 25
table.remove(arr, 3)        -- 删除位置 3 的元素
table.sort(arr)             -- 排序

索引可以不是从 1 开始,甚至可以是负数:

local arr = {}
for i = -2, 2 do
    arr[i] = i * 2
end
print(arr[-2])    --> -4
print(arr[2])     --> 4

多维数组:table 里套 table。

local matrix = {}
for i = 1, 3 do
    matrix[i] = {}
    for j = 1, 3 do
        matrix[i][j] = i * j
    end
end
print(matrix[2][3])    --> 6

十、Table(表)

Table 是 Lua 的终极数据结构 —— 数组 + 哈希表 + 对象 + 模块,一个 table 全搞定。

10.1 构造

-- 空表
local t = {}

-- 数组形式(默认 key 为 1, 2, 3...)
local t = {"apple", "pear", "orange"}

-- 字典形式
local t = {key1 = "val1", key2 = "val2"}

-- 混合
local t = {name = "Tom", 10, 20, 30}

10.2 访问

t[1]              -- 用数字索引
t["key1"]         -- 用字符串索引
t.key1            -- 字符串键的语法糖(等价于 t["key1"])

-- 访问不存在的键返回 nil
print(t["none"])     --> nil

10.3 Table 是引用类型

local a = {1, 2, 3}
local b = a          -- b 和 a 指向同一个 table
b[1] = 100
print(a[1])           --> 100(a 也被改了)

a = nil              -- 只清掉变量 a,b 还能访问 table
-- 等 b 也被 nil 时,GC 才会回收

10.4 Table 库操作

-- 连接
table.concat({"a","b","c"}, ",")     --> "a,b,c"
table.concat({"a","b","c"}, ",", 2, 3)  --> "b,c"

-- 插入/删除
table.insert(t, val)                  -- 末尾插入
table.insert(t, pos, val)            -- 指定位置插入
table.remove(t)                       -- 删除最后一个
table.remove(t, pos)                  -- 删除指定位置

-- 排序
table.sort(t)                         -- 升序
table.sort(t, function(a, b) return a > b end)   -- 降序

注意#t只在数组部分"连续"时可靠。如果中间有空洞(nil),#的行为是不确定的。要取真实长度建议遍历:

function table_len(t)
    local n = 0
    for k, v in pairs(t) do n = n + 1 end
    return n
end

十一、迭代器

11.1 pairs vs ipairs

-- ipairs:遍历数组部分,从 1 到第一个 nil 为止
local t = {10, 20, 30, key = "val"}
for i, v in ipairs(t) do
    print(i, v)          -- 1 10, 2 20, 3 30(key="val" 不输出)
end

-- pairs:遍历所有键值对(顺序不定)
for k, v in pairs(t) do
    print(k, v)          -- 输出所有的
end

11.2 自定义迭代器

-- 闭包方式
function elementIterator(tbl)
    local index = 0
    return function()
        index = index + 1
        if index <= #tbl then
            return tbl[index]
        end
    end
end

for elem in elementIterator({"a", "b", "c"}) do
    print(elem)
end

十二、模块与包

-- module.lua —— 一个模块就是一个返回 table 的文件
local M = {}                 -- 建议用 local

M.constant = "这是一个常量"

function M.func1()
    print("公有函数")
end

local function func2()       -- local 表示私有,外部不可见
    print("私有函数")
end

function M.func3()
    func2()
end

return M                     -- 返回
-- 加载模块
local m = require("module")   -- require 返回模块 table
print(m.constant)             --> 这是一个常量
m.func3()                     --> 私有函数

require 加载机制

  1. package.path中按顺序搜索 .lua文件
  2. 找不到则从 package.cpath中搜索 .so/.dll(C 扩展)
  3. 每个模块只加载一次,结果缓存到 package.loaded

自定义搜索路径:

export LUA_PATH="~/lua/?.lua;;"

十三、元表(Metatable)

元表是 Lua 对象系统的核心。通过元表,可以重载操作符、控制对表的访问。

-- 设置元表
local t = {}
local mt = {}
setmetatable(t, mt)
print(getmetatable(t))     -- 返回 mt

13.1 __index(找不到键时触发)

-- 让表有"继承"行为
local parent = {name = "parent", age = 100}
local child = setmetatable({}, {__index = parent})
print(child.name)          --> "parent"(从 parent 表中找到)

-- __index 也可以是函数
local t = setmetatable({key1 = "val1"}, {
    __index = function(tbl, key)
        if key == "key2" then return "default2" end
    end
})
print(t.key1, t.key2)      --> val1   default2

13.2 __newindex(给不存在的键赋值时触发)

local mt = {}
local t = setmetatable({key1 = "val1"}, {__newindex = mt})

t.newkey = "new"              -- 新键 → 触发 __newindex,值存到 mt
print(t.newkey, mt.newkey)    --> nil   new

t.key1 = "changed"            -- 已存在的键 → 直接赋值,不触发
print(t.key1, mt.key1)        --> changed   nil

-- 配合 rawset 实现拦截
t = setmetatable({key1 = "val1"}, {
    __newindex = function(tbl, key, value)
        rawset(tbl, key, '"' .. value .. '"')   -- 绕过元表直接赋值
    end
})
t.key2 = 4
print(t.key2)     --> "4"

13.3 操作符重载

-- 两个 table 相加
local mt = {
    __add = function(a, b)
        local result = {}
        for _, v in ipairs(a) do table.insert(result, v) end
        for _, v in ipairs(b) do table.insert(result, v) end
        return result
    end
}

local t1 = setmetatable({1, 2, 3}, mt)
local t2 = {4, 5, 6}
local t3 = t1 + t2        -- {1, 2, 3, 4, 5, 6}
元方法运算符元方法运算符
__add+__sub-
__mul*__div/
__mod%__unm-(一元)
__concat..__eq==
__lt<__le<=

13.4 __call(让 table 像函数一样被调用)

local t = setmetatable({1, 2, 3}, {
    __call = function(tbl, ...)
        local sum = 0
        for _, v in ipairs(tbl) do sum = sum + v end
        for _, v in ipairs({...}) do sum = sum + v end
        return sum
    end
})

print(t(10, 20, 30))     --> 66(1+2+3 + 10+20+30)

13.5 __tostring

local t = setmetatable({10, 20, 30}, {
    __tostring = function(tbl)
        local sum = 0
        for _, v in ipairs(tbl) do sum = sum + v end
        return "表元素之和为 " .. sum
    end
})
print(t)     --> 表元素之和为 60

十四、协同程序(Coroutine)

非抢占式"微线程",手动切换控制权,适合协作式多任务。

14.1 核心函数

函数说明
coroutine.create(f)创建协程,参数是一个函数
coroutine.resume(co, ...)启动/恢复协程,可传参
coroutine.yield(...)挂起协程,返回值给 resume
coroutine.status(co)状态:running/ suspended/ dead
coroutine.wrap(f)类似 create,但返回一个函数而非协程对象
coroutine.running()返回当前运行的协程

14.2 基本流程

local function foo()
    print("foo 开始")
    local value = coroutine.yield("暂停")   -- 挂起,返回 "暂停"
    print("foo 恢复,收到: " .. value)
end

local co = coroutine.create(foo)

local ok, result = coroutine.resume(co)      -- 启动
print(result)                                --> 暂停

ok, result = coroutine.resume(co, 42)        -- 恢复并传入 42
-- 输出:foo 恢复,收到: 42

14.3 生产者-消费者

local co

function send(x)
    coroutine.yield(x)         -- 挂起自己,把数据送出去
end

function receive()
    local ok, value = coroutine.resume(co)
    return value
end

co = coroutine.create(function()
    local i = 0
    while true do
        i = i + 1
        send(i)                -- 生产数据
    end
end)

-- 消费
for _ = 1, 5 do
    print(receive())           -- 1 2 3 4 5
end

十五、文件 I/O

15.1 简单模式(操作默认文件)

-- 读
file = io.open("test.txt", "r")
io.input(file)
print(io.read())          -- 读一行
io.close(file)

-- 写
file = io.open("test.txt", "a")
io.output(file)
io.write("-- 尾部追加注释\n")
io.close(file)

15.2 完全模式(操作指定文件句柄)

local file = io.open("test.txt", "r")
print(file:read())         -- 读一行
file:close()

file = io.open("test.txt", "a")
file:write("-- appending\n")
file:close()

15.3 打开模式

模式说明
"r"只读,文件必须存在
"w"只写,存在则清空,不存在则创建
"a"追加写
"r+"可读写,文件必须存在
"w+"可读写,存在则清空
"a+"读写 + 追加
"b"二进制模式(附加在以上模式后,如 "rb"

15.4 read 参数

file:read("*n")       -- 读一个数字
file:read("*a")       -- 读整个文件
file:read("*l")       -- 读一行(默认)
file:read(10)         -- 读 10 个字符

15.5 文件定位

file:seek("set", 0)     -- 移动到开头
file:seek("cur", 10)    -- 从当前位置移 10 字节
file:seek("end", -25)   -- 从尾部往前 25 字节
file:seek()             -- 返回当前位置

15.6 按行遍历

for line in io.lines("test.txt") do
    print(line)
end

十六、错误处理

16.1 assert

local function add(a, b)
    assert(type(a) == "number", "a 不是数字")
    assert(type(b) == "number", "b 不是数字")
    return a + b
end
add(10)     -- 报错: b 不是数字

16.2 error

error("自定义错误信息")       -- level=1,在 error 位置报错
error("错误", 2)              -- level=2,在上层调用处报错

16.3 pcall(安全调用)

local ok, result = pcall(function()
    return 10 / 0
end)

if ok then
    print("成功:", result)
else
    print("出错:", result)      -- result 是错误信息
end

16.4 xpcall(带错误处理的安全调用)

local function handler(err)
    print("捕获错误:", err)
    print(debug.traceback())     -- 打印调用栈
end

local ok = xpcall(
    function() error("出错了!") end,
    handler
)

十七、调试

debug.traceback("自定义消息")     -- 打印调用栈
debug.getinfo(1)                 -- 返回当前函数的信息表
debug.getupvalue(func, i)        -- 获取闭包/函数的第 i 个 upvalue
debug.setupvalue(func, i, val)   -- 修改 upvalue
debug.getlocal(level, i)         -- 获取局部变量
debug.setlocal(level, i, val)    -- 修改局部变量

十八、垃圾回收

Lua 是自动内存管理,GC 是递增式标记-扫描。一般不用手动干预:

collectgarbage("collect")        -- 立即执行一次完整 GC
collectgarbage("count")          -- 查看已用内存(KB)
collectgarbage("stop")           -- 暂停自动 GC
collectgarbage("restart")        -- 恢复自动 GC
collectgarbage("setpause", 150)  -- 设置间歇率
collectgarbage("setstepmul", 300)-- 设置步进倍率

十九、面向对象(用 table 模拟)

Lua 没有 class 关键字,OOP 靠 table + 元表模拟:

-- 定义"类"
Rectangle = {area = 0, length = 0, breadth = 0}

function Rectangle:new(o, length, breadth)
    o = o or {}
    setmetatable(o, self)
    self.__index = self
    self.length = length or 0
    self.breadth = breadth or 0
    self.area = length * breadth
    return o
end

function Rectangle:printArea()
    print("矩形面积:", self.area)
end

-- 使用
local r = Rectangle:new(nil, 10, 20)
r:printArea()     --> 矩形面积: 200

冒号语法function obj:method(args)等价于 function obj.method(self, args),自动传入 self

继承

Shape = {area = 0}

function Shape:new(o, side)
    o = o or {}
    setmetatable(o, self)
    self.__index = self
    self.area = side * side
    return o
end

function Shape:printArea()
    print("面积:", self.area)
end

-- Square 继承 Shape
Square = Shape:new()          -- 创建 Shape 实例作为 Square 的元表

function Square:new(o, side)
    o = o or Shape:new(o, side)
    setmetatable(o, self)
    self.__index = self
    return o
end

-- 重写方法
function Square:printArea()
    print("正方形面积:", self.area)
end

local sq = Square:new(nil, 10)
sq:printArea()    --> 正方形面积: 100

附录:常见坑点

  1. 数组从 1 开始{"a","b"}的索引是 1、2,不是 0、1
  2. 0 是真值if 0 then ...会执行,只有 nilfalse是假
  3. 不等于是 ~=,不是 !=
  4. #操作用于有 nil 空洞的 table 时不可靠,遍历要真实长度用 pairs计数
  5. 默认全是全局变量,忘记 local是常见 bug
  6. tab.key只对字符串键有效tab[1]不能写成 tab.1
  7. 连接用 ..,不能用 +
  8. 没有 continue,用 goto代替
  9. 嵌套注释不合法--[[里面不能再有 --[[
  10. 函数可以返回多个值,用多重赋值接收
  11. 元表是实现 OOP 的核心机制__index实现继承,__newindex实现拦截
  12. Lua 的"正则"是自己发明的模式匹配,和 PCRE 不一样,换语法时注意差异

Lua 的灵魂就是「简单 + 可嵌入」。table 一把梭解决了所有数据结构问题,元表提供了强大的行为定制能力。学 Lua 的关键是理解 table 和 metatable 这套机制,其他语法基本上是 C 系的熟悉面孔。

有勇气承担命运这才是英雄好汉。——黑塞
0 不喜欢
说说我的看法 -
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号