将对象传递到 Lua 函数中总是引用 self

  • 本文关键字:引用 self 函数 Lua 对象 lua
  • 更新时间 :
  • 英文 :


我正在尝试在Lua中创建一个对象("房间"(,该对象具有检查另一个提供的房间是否与它相交的功能。

我遇到了一个问题,即我作为参数传入的任何内容似乎总是与我调用函数的对象相同。

Room = {
Width = 0,
Height = 0,
X = 0,
Left = 0,
Right = 0,
Top = 0,
Bottom = 0
}
function Room:new(width, height, x, y)
self.Width = width
self.Height = height
self.X = x
self.Y = y
self.Left = x
self.Right = self.X + self.Width
self.Top = y
self.Bottom = self.Y + self.Height
return self
end
function Room:Intersects(other)
print("Checking for intersection...")
print("Self X: ", self.X)
print("Self Y: ", self.Y)
print("Other X: ", other.X)
print("Other Y: ", other.Y)
return other.Left < self.Right and self.Left < other.Right and other.Top < self.Bottom and self.Top < other.Bottom
end
room1 = Room:new(5, 6, 3, 3)
room2 = Room:new(10, 16, 5, 9)
intersects = room1:Intersects(room2)
print("Intersects: ", intersects)

输出:

$ lua FunctionTest.lua 
Checking for intersection...
Self X:     5
Self Y:     9
Other X:    5
Other Y:    9
Intersects:     true

我期待self.Xself.Yother.Xother.Y不同。我一直在关注Lua.org关于面向对象编程的章节。

Room是在顶部定义的单个表,对 Room 的所有引用都作用于同一个表而不是不同的对象。

下面的解决方案创建一个名为"obj"的不同表,并在每次调用 NewRoom(( 时返回此唯一表。 此方法与您引用的指南的第 16.4 章大致相似。

function NewRoom(width, height, x, y)
local obj = {
Width = width,
Height = height,
X = x,
Y = y,
Left = x,
Right = x + width,
Top = y,
Bottom = y + height,
}
function obj:Intersects(other)
print("Checking for intersection...")
print("Self X: ", self.X)
print("Self Y: ", self.Y)
print("Other X: ", other.X)
print("Other Y: ", other.Y)
return other.Left < self.Right and self.Left < other.Right and other.Top < self.Bottom and self.Top < other.Bottom
end
return obj
end
room1 = NewRoom(5, 6, 3, 3)
room2 = NewRoom(10, 16, 5, 9)
intersects = room1:Intersects(room2)
print("Intersects: ", intersects)

正如 Dahk 所说,您定义的 Room 表也是您作为"新"Room 对象返回的表。Room:method(...)Room.method(Room, ...)的语法简写

Lua 提供的self变量包含对 Room 的引用,当您使用速记时,Room:new(5, 6, 3, 3)Lua 读取的内容与self = RoomRoom.new(Room, 5, 6, 3, 3)。当我们self.width = 5发生的事情是Room.width = 5,这不是我们想要发生的事情。

为了解决这个问题,我们需要在每次调用Room:new时创建一个新对象。我们创建一个名为 obj 的新表,然后将值存储在其中。

function Room:new(width, height, x, y)
local obj = {
Width = width,
Height = height,
X = x,
Y = y,
Left = x,
Right = x + width,
Top = y,
Bottom = y + height,
}
return obj
end

这很好用,我们现在可以创建房间了。但是当我们尝试执行room1:Intersects(other)时,我们得到一个错误:method Intersects not defined.我们可能已经定义了一个新的房间,但这个房间只不过是一张简单的桌子。这就是元表的用武之地。简单地说,元表定义了表的行为。在我们的例子中,我们希望它包含一个 Lua 在原始列表中找不到值或方法时查看的内容。(有关元表的更多信息,请参阅第 13 章。

让我们看一个例子:
如果每个房间的地板都是一样的,我们可以把这个楼层复制到每个孩子身上,或者当有人问我们某个房间的地板是什么时,我们Room.floor = "Carpet"回到这个楼层。回到这一点,我们使用元表和__index方法。这种方法是Lua将查找它找不到的值的地方。

function Room:new(width, height, x, y)
local obj = {
...
}
setmetatable(obj, self) -- self here is equal to Room
self.__index = self
return obj
end

同样,我们创建具有要为每个房间单独存储的所有值的对象。其次,我们让Room成为obj的元表。第三行告诉我们,当找不到任何方法时,应使用房间表。
在创建对象期间使用self.__index = self与定义 Room 本身时编写Room.__index = Room相同,但当您每次都复制相同/相似的代码时会有所帮助:)
如果我们定义了该Room.floor = "Carpet"print(room1.floor)的结果将是预期的 Carpet。room1.floor的值是nil,然后 Lua 将在 room1 的元表中查找一个__index,在那里它发现 Room 可能包含它正在寻找的内容。事实上,Room.floor是被定义的,所以这就是Lua认为的答案。

总结

您还可以设置一个 metable 并使用__index方法根据需要定义对象。我认为它也可能更有效的内存效率,因为您不会为同一类的每个对象单独定义每个函数。


另外,如果您想在执行类似room1:intersects(room1)之类的操作时Room:Intersects给出 false,只需添加self ~= other即可。只有当selfother是完全相同的表时,这才会成功,即使房间的所有值都相同,它们也不会相等并且相互交叉。

相关内容

  • 没有找到相关文章

最新更新