彻底搞懂Lua闭包

一、基础:词法作用域

在深入闭包之前,我们必须先理解一个前置概念:词法作用域

Lua 具有词法作用域,这意味着变量的可见范围是由其声明所在的代码块决定的 。 在Lua 中,变量的作用域从声明开始,直到包含该声明的最内部块结束为止。 未用 local 关键字声明的变量默认为全局变量。

Lua 词法作用域的特点:

  • 局部变量: 使用 local 关键字声明的变量只在它们被声明的代码块(如 do...end 或函数体)内有效。

  • 全局变量: 不使用 local 声明的变量是全局变量,在整个程序中都可见。

  • 嵌套函数和闭包: 词法作用域使得内部函数可以访问外部函数的变量,这种机制是通过 upvalue 来实现的,它们共同构成了闭包。

  • 块作用域: Lua 没有传统意义上的块级作用域,只区分全局和局部作用域。 对于用 local 声明的变量,它们的作用域是词法确定的,而不是基于传统的块(如C++ 中的 iffor 块)。

二、闭包的实现:使用函数作为返回值

把内部函数作为 outer_function返回值

lua 复制代码
function make_printer()
    local outer_var = "I am remembered!"

    -- 创建并返回这个内部函数
    return function()
        print(outer_var)
    end
end

-- 1. 调用 make_printer,它返回了内部的那个匿名函数
local my_printer = make_printer()

-- 2. 注意!此时 make_printer() 已经执行完毕了!
--    理论上,它的局部变量 outer_var 应该已经被销毁了,但是因为内部的内部函数还在引用,所以并未真正销毁。

-- 3. 但当我们调用返回的函数时...
my_printer() -- 输出: I am remembered!

这就是一个最简单的闭包my_printer 不仅仅是一个函数,它是一个闭包实例 ,它"关闭并包围"了它需要的非局部变量 outer_var。这个被捕获的变量 outer_var 在 Lua 中被称为Upvalue

三、闭包是独立的:一座工厂,多个实例

闭包最强大的地方在于,每次调用外部的"工厂函数",都会创建一个全新的、独立的闭包,拥有自己独立的 Upvalue 实例。

让我们看一个经典的计数器例子:

lua 复制代码
function make_counter()
    local count = 0
    return function()
        count = count + 1
        return count
    end
end

-- 创建第一个计数器
local counter_A = make_counter()
print(counter_A()) -- 输出: 1
print(counter_A()) -- 输出: 2

-- 创建第二个、完全独立的计数器
local counter_B = make_counter()
print(counter_B()) -- 输出: 1 (它有自己的 count,从 0 开始)
print(counter_A()) -- 输出: 3 (counter_A 的 count 不受影响)
print(counter_B()) -- 输出: 2 

make_counter 就像一个工厂。每次调用它,都会生产出一个新的计数器。每个计数器都有自己私有的、互不干扰的 count 变量。count 对于外界是完全隐藏的,只能通过返回的那个函数来间接操作。

结语

点个赞,关注我获取更多实用 Lua 技术干货!如果觉得有用,记得收藏本文!

相关推荐
寒水馨11 分钟前
macOS下载、安装 Tailwind CSS-v4.3.3(附安装包tailwindcss-macos-arm64)
前端·css·macos·tailwind css·utility-first·css 框架·实用优先
shawxlee25 分钟前
vue3+axios挑战最简洁实用的配置封装+接口调用:请求拦截器、响应拦截器、通用请求方法(单个请求/并发请求/下载文件)、统一接口管理
前端·经验分享·vue·接口·axios·api
yuhaiqiang1 小时前
上线一个人静态网站需要多少钱,难不难?
前端·后端·程序员
宸津-代码粉碎机1 小时前
Jar热部署进阶实战|修复原生方案OOM与类冲突问题,生产级无BUG优化方案
java·大数据·服务器·开发语言·前端·人工智能·python
寒水馨1 小时前
macOS下载、安装neovim-v0.12.4(附安装包nvim-macos-arm64.tar.gz)
macos·vim·lua·文本编辑器·终端·lsp·neovim
To_OC9 小时前
写了三遍 Todo List,我终于搞懂了 React 父子组件到底怎么通信
前端·javascript·react.js
勇往直前plus10 小时前
Vue3(篇一) 核心概念——响应式模板语法与组件基础
前端·javascript·vue.js
咩咩啃树皮10 小时前
第43篇:Vue3计算属性(computed)完全精讲——缓存机制、依赖计算、业务最优解
前端·vue.js·缓存
徐小夕12 小时前
花了一周,3亿tokens,我开源了一款 Word 文档智能审查平台,文稿自动质检+可视化分析,告别低效人工审核
前端·算法·github
kyriewen13 小时前
别再乱用useEffect了——你写的10个里有8个不该存在
前端·javascript·react.js