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

将对象传递给Lua函数总是引用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 = wi

我试图在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)

我希望self.X,self.Y与其他.X和其他.Y不同。我一直在关注Lua.org的章节。

房间是顶部定义的一个表,对房间的所有引用都作用于同一个表,而不是不同的对象

下面的解决方案创建一个名为“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)

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.methodRoom

当您使用速记时,Lua提供的self变量包含对Room的引用,因此当您键入Room:new5、6、3、3时,Lua读取的是Room.newRoom,5、6、3、3,其中self=Room。当我们让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:Intersect时,我们得到了一个错误:方法Intersects未定义。我们可能定义了一个新房间,但这个房间只不过是一张简单的桌子。这就是元表的用武之地。简言之,元表定义了表的行为。在我们的例子中,我们希望它包含一个值,以便Lua在原始列表中找不到值或方法时可以查看。有关元表的更多信息,请参见

让我们看一个例子: 如果每个房间的地板都是一样的,我们可以把这个地板复制给每个孩子,或者让room.floor=地毯,当有人问我们某个房间的地板是什么时,我们就回到这里。回到这里,我们使用元表和方法。这个方法是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.\uuuu index=self与在定义文件室本身时使用writing Room.\uuuu index=Room相同,但在每次复制相同/类似代码时都会有所帮助: 如果我们已定义Room.floor=地毯,则printroom1.floor的结果将是预期的地毯。room1.floor的值为nil,然后Lua将在room1的元表中查找_索引,在该索引中,它发现该房间可能包含它所查找的内容。事实上,Room.floor是有定义的,这就是Lua所看到的答案

总结 您还可以设置一个元文件,并使用_index方法来定义您希望执行的对象。我认为这可能会提高内存效率,因为您没有为同一类的每个对象分别定义每个函数


另外,如果您想在执行类似于room1:intersectsroom1的操作时使用Room:Intersects give false,只需添加self~=other。只有当self和other是完全相同的表时,该操作才会成功,即使房间的所有值都相同,它们也不会相等并相互相交。

正如Dahk所说,您定义的房间表也是作为新房间对象返回的房间表。 房间:方法。。。是Room.methodRoom

当您使用速记时,Lua提供的self变量包含对Room的引用,因此当您键入Room:new5、6、3、3时,Lua读取的是Room.newRoom,5、6、3、3,其中self=Room。当我们让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:Intersect时,我们得到了一个错误:方法Intersects未定义。我们可能定义了一个新房间,但这个房间只不过是一张简单的桌子。这就是元表的用武之地。简言之,元表定义了表的行为。在我们的例子中,我们希望它包含一个值,以便Lua在原始列表中找不到值或方法时可以查看。有关元表的更多信息,请参见

让我们看一个例子: 我 如果每个房间的地板都是一样的,我们可以把这个地板复制给每个孩子,或者让room.floor=地毯,当有人问我们某个房间的地板是什么时,我们就回到这个房间。回到这里,我们使用元表和方法。这个方法是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.\uuuu index=self与在定义文件室本身时使用writing Room.\uuuu index=Room相同,但在每次复制相同/类似代码时都会有所帮助: 如果我们已定义Room.floor=地毯,则printroom1.floor的结果将是预期的地毯。room1.floor的值为nil,然后Lua将在room1的元表中查找_索引,在该索引中,它发现该房间可能包含它所查找的内容。事实上,Room.floor是有定义的,这就是Lua所看到的答案

总结 您还可以设置一个元文件,并使用_index方法来定义您希望执行的对象。我认为这可能会提高内存效率,因为您没有为同一类的每个对象分别定义每个函数

另外,如果您想在执行类似于room1:intersectsroom1的操作时使用Room:Intersects give false,只需添加self~=other。只有当self和other是完全相同的表时,才能成功,即使房间的所有值都相同,它们也不会相等并相互相交