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