在Lua编程中,闭包允许函数访问其外部作用域的变量。这些被访问的外部变量在Lua内部被称为"上值"(upvalue)。
什么是上值(Upvalue)?
上值指的是被内部函数访问的外部局部变量。
Lua
function create_counter()
local count = 0 -- 这是一个上值
return function()
count = count + 1 -- 访问上值
return count
end
end
local counter = create_counter()
print(counter()) -- 输出: 1
print(counter()) -- 输出: 2
在这个例子中,`count`变量就是上值,它被内部函数访问,即使外部函数`create_counter`已经返回。
上值的两种状态
当外部函数仍在执行时,上值处于开放状态。此时:
- 上值仍然存在于栈上
- UpVal结构只保存指向栈的指针
- 多个闭包可以共享同一个上值
当外部函数返回后,如果仍有闭包引用该上值,则上值转为关闭状态:
- 值从栈复制到UpVal结构内部
- 不再依赖栈的存在
- 可以独立存在
源码:UpVal结构
cpp
typedef struct UpVal {
TValue *v; /* 指向实际值的位置 */
lu_mem refcount; /* 引用计数 */
union {
struct { /* 开放状态:链表管理 */
UpVal *next;
int touched;
} open;
TValue value; /* 关闭状态:值存储 */
} u;
} UpVal;
状态从开放到关闭的转换过程
之所以外部函数返回了,仍能访问到变量,就是存在这样的过程,把上值的值复制到内部保存起来,然后指针从指向栈改成指向内部成员值。
cpp
// 1. 将值从栈复制到UpVal内部
setobj(L, &uv->u.value, uv->v);
// 2. 更新指针指向内部存储
uv->v = &uv->u.value;
// 3. 设置垃圾回收屏障
luaC_upvalbarrier(L, uv);
实际应用
状态管理
Lua
function create_state_machine(initial_state)
local current_state = initial_state
local states = {}
return {
get_state = function() return current_state end,
set_state = function(new_state)
current_state = new_state
end,
add_state = function(name, handler)
states[name] = handler
end
}
end
缓存
Lua
function create_cache()
local cache = {}
local max_size = 100
return {
get = function(key) return cache[key] end,
set = function(key, value)
if #cache >= max_size then
-- 简单的LRU实现
local oldest = next(cache)
cache[oldest] = nil
end
cache[key] = value
end,
clear = function() cache = {} end
}
end
单例
Lua
local singleton = (function()
local instance = nil
return function()
if not instance then
instance = create_instance()
end
return instance
end
end)()