You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Lua代理表封装Account对象报错,求nil索引问题解决方案

问题分析与解决方案

错误原因

你遇到的 attempt to index a nil value (field '?') 错误,是因为调用方法时使用了点语法而非冒号语法。Lua中,用冒号定义的方法会自动将调用者作为第一个参数(即self)传入;而点语法不会,导致方法里的self变成了你传入的数值(比如100.0),此时accounts[self]自然是nil,进而引发索引nil的错误。

修正后的代码

local AccountProxy = {}

-- 内部表:代理对象到实际账户表的映射,对外不可访问
local accounts = {}

function AccountProxy:new()
    local proxy = {}
    local account = {balance = 0}
    accounts[proxy] = account

    setmetatable(proxy, {   
        __index = self,
    })

    return proxy
end

function AccountProxy:withdraw(v)
    accounts[self].balance = accounts[self].balance - v
end

function AccountProxy:deposit(v)    
    accounts[self].balance = accounts[self].balance + v     
end

function AccountProxy:getBalance()
    return accounts[self].balance
end

-- 示例用法:使用冒号语法调用方法
local acc_1 = AccountProxy:new() 
 
acc_1:deposit(100.0) 
print(acc_1:getBalance())  -- 输出100.0
acc_1:withdraw(50.0)
print(acc_1:getBalance())  -- 输出50.0

代理实现方式的优缺点

优点

  • 严格封装:内部账户状态(balance)完全隐藏在accounts表中,外部无法直接访问或修改,只能通过提供的方法操作,确保数据安全性。
  • 灵活的元表控制:可以通过元表的__index、__newindex等元方法添加额外逻辑(比如访问日志、权限校验),而无需修改实际对象的结构。
  • 内存效率:代理对象本身是空表,仅作为标识映射到实际状态表,在某些场景下能减少对象本身的内存占用。

缺点

  • 性能开销:每次方法调用都需要通过accounts[self]查找实际对象,比直接操作对象属性多了一层查找,频繁调用时会有性能损耗。
  • 调试难度:由于状态存储在内部表,调试时无法直接通过代理对象查看balance的值,需要额外的调试方法或工具。
  • 代码复杂度:相比直接的对象实现,多了一层代理映射,增加了代码的理解和维护成本。

内容的提问来源于stack exchange,提问作者kos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 18:16:04