尝试在 Lua 中实现面向对象编程,但出现问题
好的,我试图遵循这里的指示: https://www.lua.org/pil/16.1.html,在 Lua (和 LOVE 游戏框架)中实现类似面向对象编程,但是出现了一些问题。这是我的代码核心部分。我有一个通用的 Object 类:
local Object = {}
function Object:load(arg)
end
function Object:update(dt)
end
function Object:draw()
end
function Object:new(arg)
o = {}
setmetatable(o, self)
self.__index = self
o:load(arg)
return o
end
return Object
还有一个由它继承的 Ship 类:
Object = require('objects.object')
local Ship = Object:new()
Ship.sprite = love.graphics.newImage('assets/sprites/ship.png')
Ship.sprite:setFilter('nearest', 'nearest', 0)
Ship.px = Ship.sprite:getWidth()/2
Ship.py = Ship.sprite:getHeight()/2
function Ship:load(arg)
self.x = arg.x or 0
self.y = arg.y or 0
self.sx = arg.sx or arg.s or 1
self.sy = arg.sy or arg.s or 1
self.rot = arg.rot or 0
self.tint = arg.tint or {255, 255, 255}
end
function Ship:draw()
love.graphics.setColor(self.tint)
love.graphics.draw(self.sprite, self.x, self.y, self.rot,
self.sx, self.sy, self.px, self.py)
love.graphics.setColor({255, 255, 255})
end
return Ship
现在的问题是,我用这段代码在另一个对象中创建了两个 Ship 的实例:
self.ship1 = Ship:new({x=50, y=self.y1, s=2, tint={0, 0.5, 1}})
self.ship2 = Ship:new({x=750, y=self.y2, s=-2, tint={1, 0.5, 0}})
但当我绘制它们时,我只看到了一个(第二个)。事实证明,就像上面的代码没有将新的 Ship 实例分配给 ship1 和 ship2 一样,而是直接分配给了 self,原因我无法理解。是我做错了哪些事情,还是解释器中的一个奇怪的 bug?
这不是解释器的 bug,它是语言的设计行为。 o = {} 创建了全局变量,这不是程序员预期的结果。 "为什么会这样?" 是向语言创作者经常问的问题。有很多努力使得控制这种行为更简单。
o = {} 没有 local 创建全局变量,该全局变量在程序中的所有函数中都是可访问和共享的,除非使用精密的环境作用域技术。在函数内部使用全局变量会打开各种副作用的门,你应该小心副作用。
我删除了一些语法糖并添加了上面的代码,可以等价地编写如下:
Object.new = function(table_before_colon,arg)
highlander = {} --全局变量,只能有一个
setmetatable(highlander,table_before_colon);
table_before_colon.__index = table_before_colon;
highlander:load(arg) -- table_before_colon.__index.load(highlander,arg)
return highlander
end
local Ship = Object:new()
-- 全局高地人 == Ship
--Ship.new 指向 Object.new
function Ship:load(arg)--等同于:Ship.load=function(self,arg)
--设置“self”对象字段并从 new 中调用的代码
self.x = arg.x or 0 -- 相当于 highlander.x=arg.x or 0
end
现在,如果从 new 开始到 new 返回的这段时间内没有对全局变量做任何操作,那么全局变量的存在就不再重要了。但是,显然,你的其他代码类似于这样:
local OtherObject = Object:new()
--otherObject == 全局高地人
OtherObject.load = function(new_other_obj,arg)
--highlander == new_other_obj
new_other_obj.ship1 = Ship:new({x=50, y=self.y1, s=2, tint={0, 0.5, 1}})
--highlander == new_other_obj.ship1
new_other_obj.ship2 = Ship:new({x=750, y=self.y2, s=-2, tint={1, 0.5, 0}})
--highlander == new_other_obj.ship2
end
因此,OtherObject.load 调用其他函数,那些函数也访问和修改相同的全局变量。
local some_object = OtherObject:new()
返回的是在调用结束时全局变量的值,这个全局变量最后设为 OtherObject.load 中 Ship:new 调用中的 ship2,该调用是在调用 OtherObject.load 中的调用中完成的,这个调用又在 OtherObject:new 的调用中完成。
- Lua 虚拟机加密load(string.dump(function)) 后执行失败问题如何解决
- 我想创建一个 Nginx 规则,禁止访问
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?

已解决!显然,需要这个小片段:
function Object:new(arg) local o = {} setmetatable(o, self) self.__index = self o:load(arg) return o end在所有的
new方法中将o设置为局部变量解决了一切。我不知道它为什么可以工作,但是我假设当元表被设置时,把它放在全局变量空间中会破坏一些东西。