3Programming in Lua(第4版)

函数与闭包

函数式编程

函数闭包尾调用泛型for

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第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())  -- 150

2.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)?


3/8函数与闭
0%