0Pricing
Lua Academy · 课时

闭包之间共享上值

了解多个闭包共享同一个上值及其变更带来的影响。

闭包之间共享上值 是 CoddyKit 上的免费 Lua Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Lua Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Lua Academy 课程共包含 4 节课。

共享同一个上值

在同一作用域中定义的两个闭包可以共享完全相同的上值单元。其中一个闭包进行的修改,另一个闭包也能看到。

local function makeGetterSetter()
  local value = 0
  local function get() return value end
  local function set(v) value = v end
  return get, set
end
local get, set = makeGetterSetter()
set(42)
print(get())  -- 42

为什么会发生共享

Lua 不会为每个闭包复制上值。在同一代码块中创建、并指向同一个局部变量的所有闭包,都会共享一个上值单元。

通过共享上值实现观察者模式

共享上值可以充当多个闭包之间的消息总线。

local count = 0
local inc = function() count = count + 1 end
local dec = function() count = count - 1 end
local get = function() return count end
inc(); inc(); dec()
print(get())  -- 1

循环变量的陷阱

在 numeric for 循环中,每次迭代都会创建一个新的局部循环变量,因此闭包捕获的是彼此独立的上值。

local fns = {}
for i = 1, 3 do
  fns[i] = function() return i end
end
print(fns[1](), fns[2](), fns[3]())  -- 1 2 3 (each closure has its own i)

while 循环变量的陷阱

在 while 循环中,如果闭包捕获的是一个会发生变化的变量,那么所有闭包都会共享同一个上值,并看到最终值。

local fns = {}
local i = 0
while i < 3 do
  i = i + 1
  fns[i] = function() return i end  -- all share same i!
end
print(fns[1]())  -- 3 (not 1!)

捕获新的局部变量

要在 while 循环中捕获彼此独立的值,请在循环体内引入新的局部变量。

local fns = {}
local i = 0
while i < 3 do
  i = i + 1
  local ci = i  -- new local per iteration
  fns[i] = function() return ci end
end
print(fns[1]())  -- 1, fns[2]() == 2

共享状态模块模式

模块可以通过上值,让多个函数共享一个私有状态表。

local function makeStack()
  local data = {}
  return {
    push = function(v) data[#data+1] = v end,
    pop  = function() local v = data[#data]; data[#data]=nil; return v end,
    size = function() return #data end,
  }
end

别名与修改

请注意:所有引用同一个上值的闭包都会立即看到相同的修改。这种机制很强大,但也可能造成意外的耦合。

上值标识

debug.upvalueid(f, n) 返回函数 f 第 n 个上值的唯一标识。具有相同上值 ID 的两个闭包共享同一个单元。

debug.upvaluejoin

debug.upvaluejoin(f1, n1, f2, n2) 让 f1 的第 n 个上值与 f2 的第 n 个上值共享同一个单元。这是用于调试的底层工具。

实用模式

  • 共享私有变量的获取器/设置器组合。
  • 通过多个闭包暴露重置功能的事件计数器。
  • 多个 API 函数共享的模块状态。

共享上值问题

在同一作用域中创建了两个闭包 get 和 set,它们都捕获了 value。如果调用 set(99),get() 会返回什么?

回顾:共享上值

同一作用域中的闭包会共享上值单元。所有共享闭包都会立即看到修改后的值。这是 Lua 中实现封装和模块状态的基础。

常见问题解答

「闭包之间共享上值」课时是免费的吗?

是的 — 「闭包之间共享上值」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Lua Academy 课程的其余内容,请升级到 CoddyKit PRO。 Lua Academy 课程共包含 4 节课。

「闭包之间共享上值」这节课中我会学到什么?

了解多个闭包共享同一个上值及其变更带来的影响。 你通过在浏览器中直接运行的动手代码来练习 Lua Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Lua Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Lua Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「闭包之间共享上值」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Lua Academy 课中编写并运行代码吗?

能。每节 Lua Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 什么是上值?
  2. 闭包之间共享上值
  3. 工厂函数和生成器
  4. 使用闭包实现记忆化
← 返回 Lua Academy