Lua 函数
1. 课程信息
- 课题:Lua 函数基础与进阶用法
- 课时建议:60 ~ 90 分钟
- 适合对象 :已掌握 Lua 变量、流程控制(
if/for/while)与table基础的学习者
2. 教学目标
- 理解函数的作用:封装逻辑、复用代码、提升可读性
- 掌握定义与调用 :
function ... end、匿名函数、局部/全局函数 - 掌握参数与返回值 :多返回值、可变参数(
...)、选择性接收 - 理解 Lua 的"函数是一等公民":函数可赋值、可作为参数、可作为返回值
- 能写出可维护的函数:明确输入输出、处理边界、合理命名
3. 知识要点
3.1 函数的定义与调用
Lua 中最常见的写法:
lua
-- global function (not recommended in big projects)
function add(a, b)
return a + b
end
print(add(2, 3)) -- 5
更推荐的局部函数:
lua
local function add(a, b)
return a + b
end
print(add(2, 3))
3.2 函数的本质:变量里装的值
下面两段代码等价:
lua
local function add(a, b)
return a + b
end
lua
local add
add = function(a, b)
return a + b
end
强调:函数就是一种值(和数字、字符串一样),因此可以赋值/传递。
3.3 参数与返回值
3.3.1 多参数、多返回值
lua
local function divmod(a, b)
return math.floor(a / b), a % b
end
local q, r = divmod(17, 5)
print(q, r) -- 3 2
3.3.2 只接收部分返回值
lua
local function divmod(a, b)
return math.floor(a / b), a % b
end
local q = divmod(17, 5)
print(q) -- 3 (only first return value)
3.3.3 返回值数量不固定的常见场景
string.find:找到了返回位置,没找到返回nil- 自己写函数时也可以:失败返回
nil+ 错误信息
lua
local function toNumber(s)
local n = tonumber(s)
if n == nil then
return nil, "not a number"
end
return n
end
local n, err = toNumber("12x")
print(n, err) -- nil not a number
3.4 可变参数(Varargs):...
lua
local function sum(...)
local total = 0
for i = 1, select("#", ...) do
local v = select(i, ...)
total = total + v
end
return total
end
print(sum(1, 2, 3, 4)) -- 10
要点:
...表示所有传入的额外参数select("#", ...)获取可变参数数量select(i, ...)获取第i个参数
3.5 高阶函数:函数作为参数/返回值
3.5.1 函数作为参数(回调思想)
lua
local function apply(a, b, op)
return op(a, b)
end
local function mul(x, y)
return x * y
end
print(apply(2, 3, mul)) -- 6
print(apply(2, 3, function(x, y) return x - y end)) -- -1
3.5.2 返回函数(工厂函数)
lua
local function makeAdder(step)
return function(x)
return x + step
end
end
local add10 = makeAdder(10)
print(add10(7)) -- 17
3.6 闭包(Closure)与作用域
闭包:函数"记住"它被创建时所在的外部变量。
lua
local function makeCounter()
local count = 0
return function()
count = count + 1
return count
end
end
local c1 = makeCounter()
print(c1()) -- 1
print(c1()) -- 2
local c2 = makeCounter()
print(c2()) -- 1 (independent)
要点:
count是局部变量,但因为被内部函数引用,所以不会立刻释放- 适合实现计数器、缓存、封装私有状态
3.7 : 与 . 的差异(面向对象常见)
lua
local Player = {}
Player.__index = Player
function Player.new(name)
return setmetatable({ name = name }, Player)
end
function Player.say(self, msg) -- dot style requires explicit self
print(self.name .. ": " .. msg)
end
function Player:say2(msg) -- colon style passes self implicitly
print(self.name .. ": " .. msg)
end
local p = Player.new("Alice")
p.say(p, "hello")
p:say2("hello")
规则:
obj:method(x)等价于obj.method(obj, x)- 定义时用
function T:method(...),调用时也用:保持一致
4. 课堂演示(建议流程)
- Step 1(5min):用"重复代码"的例子引出函数封装
- Step 2(10min) :讲
local function与返回值 - Step 3(15min) :多返回值、
nil + err的错误返回模式 - Step 4(15min) :可变参数
...与select - Step 5(15min):高阶函数与闭包(重点)
- Step 6(10min) :
:与.的差异(结合 table + metatable 简单展示)
5. 练习题(课堂)
练习 1:写一个安全除法
实现 safeDiv(a, b):
- 当
b == 0时返回nil, "division by zero" - 否则返回
a / b
练习 2:实现 map
实现 map(arr, fn):
arr是数组 tablefn是函数:fn(value, index)- 返回一个新数组
示例:
- 输入
{1,2,3}和function(v) return v*2 end - 输出
{2,4,6}
练习 3:实现 filter
实现 filter(arr, pred):
pred(value, index)返回true/false- 返回符合条件的新数组
6. 作业(课后)
作业 1:实现一个缓存闭包
实现 memoize(fn):返回一个新函数,能缓存 fn 的计算结果。
- 只要求支持单个参数(key)即可
- 缓存用 table 保存
作业 2:实现一个小型日志系统
实现 makeLogger(prefix):
- 返回一个函数
log(msg) - 每次调用输出:
prefix .. ": " .. msg prefix由闭包保存
7. 常见坑总结
- 多返回值丢失:把函数返回值放在表达式中(如拼接、作为参数)时,常只保留第一个返回值
- 全局污染 :缺少
local容易污染全局命名空间 :与.混用 :定义用:却用.调用(或反过来)会导致self不正确- 对
nil判断不严谨 :失败返回时要同时返回nil, err,调用方要判断if not ok then ... end
8. 扩展阅读(建议)
- Lua manual:Functions / Vararg / Closures
- 学会用
pcall/xpcall做异常捕获(进阶主题)