Lua上值与闭包

在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)()
相关推荐
Terio_my6 小时前
Java bean 数据校验
java·开发语言·python
Tony Bai6 小时前
【Go开发者的数据库设计之道】07 诊断篇:SQL 性能诊断与问题排查
开发语言·数据库·后端·sql·golang
超级大只老咪7 小时前
何为“类”?(Java基础语法)
java·开发语言·前端
我笑了OvO7 小时前
C++类和对象(1)
java·开发语言·c++·类和对象
渡我白衣9 小时前
C++ 异常处理全解析:从语法到设计哲学
开发语言·c++·面试
悦悦子a啊10 小时前
[Java]PTA: jmu-Java-02基本语法-08-ArrayList入门
java·开发语言·算法
毕设源码-郭学长11 小时前
【开题答辩全过程】以 PHP茶叶同城配送网站的设计与实现为例,包含答辩的问题和答案
开发语言·php
JavaPub-rodert12 小时前
用 go-commons 打造更优雅的字符串处理工具
开发语言·后端·golang
Archie_IT12 小时前
嵌入式八股文篇——P1 关键字篇
c语言·开发语言·单片机·mcu·物联网·面试·职场和发展