第3章:函数与闭包
一、导读
1.1 本章学习目标
第3章讲解 Lua 的函数和闭包:函数作为值、闭包、尾调用。
本章核心学习目标:
- 理解函数是一等值:可以赋值、传递、返回
- 掌握闭包:函数记住定义时的环境
- 理解尾调用优化
- 掌握多重返回值
1.2 为什么本章如此重要
函数和闭包是 Lua 最强大的特性。Lua 的面向对象、模块系统都建立在闭包之上。
1.3 核心问题引导
Lua 的函数可以返回多个值吗?
闭包是如何实现的?
什么是尾调用?为什么它重要?
二、核心概念详解
2.1 函数基础
lua
-- 函数定义
function add(a, b)
return a + b
end
-- 函数是值
local mul = function(a, b) return a * b end
print(mul(3, 4)) -- 12
-- 多重返回值
function minmax(arr)
local min, max = arr[1], arr[1]
for _, v in ipairs(arr) do
if v < min then min = v end
if v > max then max = v end
end
return min, max
end
local lo, hi = minmax({3, 1, 4, 1, 5, 9})
print(lo, hi) -- 1 9
-- 可变参数
function sum(...)
local total = 0
for _, v in ipairs({...}) do
total = total + v
end
return total
end
print(sum(1, 2, 3, 4, 5)) -- 15
-- 命名参数模式
function rename(old, new)
-- ...
end
rename{old="file.txt", new="backup.txt"}2.2 闭包
lua
-- 闭包: 函数 + 它引用的上值 (upvalue)
function newCounter()
local count = 0
return function()
count = count + 1
return count
end
end
local c1 = newCounter()
print(c1()) -- 1
print(c1()) -- 2
print(c1()) -- 3
local c2 = newCounter()
print(c2()) -- 1 (独立的计数器)
-- 闭包实现私有成员
function newAccount(initialBalance)
local balance = initialBalance
local function withdraw(amount)
if amount > balance then error("insufficient funds") end
balance = balance - amount
end
local function deposit(amount)
balance = balance + amount
end
local function getBalance()
return balance
end
return {
withdraw = withdraw,
deposit = deposit,
getBalance = getBalance
}
end
local acc = newAccount(100)
acc.deposit(50)
print(acc.getBalance()) -- 1502.3 尾调用
lua
-- 尾调用: 函数的最后一步是调用另一个函数
function factorial(n, acc)
acc = acc or 1
if n <= 1 then return acc end
return factorial(n - 1, n * acc) -- 尾调用
end
-- Lua 保证尾调用不会增加调用栈
-- 等价于 goto,可以无限递归
-- 非尾调用
function bad_factorial(n)
if n <= 1 then return 1 end
return n * bad_factorial(n - 1) -- 不是尾调用 (还有乘法)
end三、实战案例
3.1 案例一:用闭包实现迭代器
lua
-- 列表的迭代器
function listIterator(list)
local i = 0
local n = #list
return function()
i = i + 1
if i <= n then return list[i] end
end
end
for item in listIterator({"a", "b", "c"}) do
print(item)
end
-- 无状态迭代器
function rangeIter(from, to)
return function(_, last)
local next = last + 1
if next > to then return nil end
return next
end, nil, from - 1
end
for i in rangeIter(1, 5) do
print(i) -- 1, 2, 3, 4, 5
end四、本章小结
函数是一等值,可以赋值、传递、返回
闭包让函数记住定义时的环境
尾调用不增加调用栈,支持无限递归
五、思考与练习
闭包的上值 (upvalue) 是引用还是拷贝?
如何实现一个带缓存的函数(memoization)?