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

Lua遍历对象列表调用成员方法时报索引数值类型错误

问题根因

报错由两处逻辑错误触发,其中直接导致运行崩溃的是表遍历语法使用错误,另一处是类实现的隐藏bug:

  • 直接报错原因:Lua 中用 pairs/ipairs 遍历表时,for 循环的第一个返回值是当前元素的键(数组场景下为数字索引),第二个返回值才是键对应的存储值。你写的 for projectile in pairs(self.projectiles) do 仅接收了第一个返回值,也就是1、2、3这类数字索引,后续对数字调用 :move() 方法自然会抛出「尝试索引number类型值」的错误。
  • 隐藏的原型污染bug:两个类的 new 构造函数中,你把传入的属性都赋值给了 self(也就是类原型表),而非新创建的实例对象 o。这会导致所有创建的实例共享同一组属性,后续修改任意实例的坐标、速度,所有投射物的属性都会被同步篡改。
  • 额外的边界bug:ProjectileGroup 初始定义的默认 projectiles 值为数字0,如果创建组时不传入projectiles参数,后续调用 add_projectile 执行 table.insert 会因为传入数字类型参数直接报错。
修复方法

1. 修正遍历逻辑

遍历表时同时接收索引和值两个返回值,不需要使用索引时可以用_做占位符。连续索引的数组场景优先用ipairs遍历,行为更稳定、性能更好:

function ProjectileGroup:move()
    for _, projectile in ipairs(self.projectiles) do
        projectile:move()
    end
end

function ProjectileGroup:log()
    for _, projectile in ipairs(self.projectiles) do
        projectile:log()
    end
end

2. 修正构造函数赋值逻辑

构造函数中所有实例属性都要赋值到新创建的实例表o上,不要修改类原型self,同时给projectiles设置合理的空表默认值:

function Projectile:new (o,x,y,z,six,siy,siz,spx,spy,spz)
   o = o or {}
   setmetatable(o, self)
   self.__index = self
   -- 所有属性绑定到实例o
   o.x = x
   o.y = y
   o.z = z
   o.six = six
   o.siy = siy
   o.siz = siz
   o.spx = spx
   o.spy = spy
   o.spz = spz
   return o
end

function ProjectileGroup:new (o,projectiles)
   o = o or {}
   setmetatable(o,self)
   self.__index = self
   -- 未传入projectiles时默认初始化为空表
   o.projectiles = projectiles or {}
   return o
end
修复后验证代码

替换上述两段逻辑后即可正常运行,调用projectileGroup:log()可以看到三个投射物的坐标已经按照各自的速度正确更新:

--Projectile class
Projectile = {x = 0, y = 0, z = 0, six = 0, siy = 0, siz = 0, spx = 0, spy = 0, spz = 0}
function Projectile:new (o,x,y,z,six,siy,siz,spx,spy,spz)
   o = o or {}
   setmetatable(o, self)
   self.__index = self
   o.x = x
   o.y = y
   o.z = z
   o.six = six
   o.siy = siy
   o.siz = siz
   o.spx = spx
   o.spy = spy
   o.spz = spz
   return o
end

function Projectile:move ()
   self.x = self.x + self.spx
   self.y = self.y + self.spy
   self.z = self.z + self.spz
end

function Projectile:log ()
    system.print('x: '..tostring(self.x)..'|y: '..tostring(self.y)..'|z: '..tostring(self.z)..'|six :'..tostring(self.six)..'|siy :'..tostring(self.siy)..'|siz :'..tostring(self.siz)..'|spx :'..tostring(self.spx)..'|spy :'..tostring(self.spy)..'|spz :'..tostring(self.spz))
end


--ProjectileGroup
ProjectileGroup = {}

function ProjectileGroup:new (o,projectiles)
   o = o or {}
   setmetatable(o,self)
   self.__index = self
   o.projectiles = projectiles or {}
   return o
end

function ProjectileGroup:add_projectile(projectile)
    table.insert(self.projectiles, projectile)
end

function ProjectileGroup:move()
    for _, projectile in ipairs(self.projectiles) do
        projectile:move()
    end
end

function ProjectileGroup:log()
    for _, projectile in ipairs(self.projectiles) do
        projectile:log()
    end
end


projectileA = Projectile:new(nil,0,0,0,10,10,10,0.1,0.3,0.4)
projectileB = Projectile:new(nil,0,0,0,10,10,10,0.4,0.2,-0.4)
projectileC = Projectile:new(nil,0,0,0,10,10,10,0.1,0.05,0.1)
projectileGroup = ProjectileGroup:new(nil,{projectileA,projectileB,projectileC})
projectileGroup:move()
projectileGroup:log()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 11:00:59