Lua依赖注入场景下‘attempt to call field run(table value)’报错排查
问题分析与修复
报错原因
1. 代码顺序导致__call元方法未正确绑定
在engine.lua中,你先执行了Engine.__call = Engine.run,但此时Engine.run函数还未定义,Lua会将nil赋值给Engine.__call。后续虽然定义了Engine.run,但Engine.__call不会自动更新为新的函数引用,始终保持nil状态。
当通过Engine(Car)创建实例时,该实例的元表是Engine,但Engine中的__call元方法为nil。调用这个实例(即Car.run(opts))时,Lua找不到触发调用的元方法,因此抛出attempt to call field 'run' (a table value)错误。
2. 模块级全局变量引发的潜在问题
Engine.new中直接给Engine.car赋值,这是模块内的全局变量,所有Engine实例会共享同一个car引用。如果后续创建多个实例,会覆盖之前的car对象,导致逻辑错误。
修复代码
修改engine.lua
调整代码顺序,确保Engine.run定义后再绑定__call,同时将car绑定到实例自身:
-- engine.lua local Engine = {} Engine.__index = Engine -- 先定义run方法 Engine.run = function(self, opts) print(self.car.name) end -- 绑定__call元方法 Engine.__call = Engine.run Engine.new = function(car) -- 将car存入实例,而非模块全局变量 local self = setmetatable({car = car}, Engine) return self end return setmetatable(Engine, { __call = Engine.new })
car.lua无需改动
-- car.lua local Car = {name = "ferrari"} local Engine = require('engine') Car.run = Engine(Car) local opts = {} Car.run(opts) -- 现在会正常输出"ferrari"
验证逻辑
修复后:
Engine.__call会正确指向Engine.run,调用Car.run(opts)时,Lua会触发实例元表的__call元方法,执行Engine.run。- 每个Engine实例都有独立的
car引用,避免了多实例间的状态污染。
内容的提问来源于stack exchange,提问作者hac_ticc
相关产品推荐
相关产品推荐

