Oop 在Lua中的新对象上指定元表

Oop 在Lua中的新对象上指定元表,oop,lua,lua-table,metatable,Oop,Lua,Lua Table,Metatable,方法/1 Dog = {} function Dog:new() local newObj = {sound = 'woof'} return setmetatable(newObj, { __index = self }) end 方法/2 Dog = {} function Dog:new() local newObj = {sound = 'woof'} self.__index = self return setmetatable(newObj, self) e

方法/1

Dog = {}
function Dog:new()
  local newObj = {sound = 'woof'}
  return setmetatable(newObj,   { __index = self })
end
方法/2

Dog = {}
function Dog:new()
  local newObj = {sound = 'woof'}
  self.__index = self
  return setmetatable(newObj, self)
end
大多数时候,我都看到人们使用self.\uu index=self方法,这在我看来很笨拙。为什么要将整个
Dog
对象以及所有不构成元表的附加方法传递给
setmetatable
Method/1有助于设置新对象的
元表。对于
Dog
对象,索引也更干净

是否有充分的理由使用方法/2而不是方法/1
一些额外的代码来提供上下文,这两种方法都可以使用

function Dog:makeSound()
  print('I say ' .. self.sound)
end

mrDog = Dog:new()
mrDog:makeSound()

方法/2方法/1更优化,因为它不需要创建额外的表作为其元表。它将自身用作元表


既然您说您认为方法/1在您的问题中更为清晰,请随意使用它。我认为在大多数情况下,两者之间的性能差异并不重要。可读性几乎总是更为重要。

虽然两种方法都实现了相同的最终行为,但有人可能更喜欢方法2,因为它更符合“回收资源优于创建”的政策。方法2将始终使用一个表
Dog
作为元表,而不管您创建了多少个Dog对象。方法1,OTOH,将创建一个新的匿名表,作为每个Dog对象的元


然而,对于语言的新手来说,方法1可能更容易阅读和理解,因为它不会将元表和对象定义的关注点混合在一起。

如果你想要一个
\ueq
元方法,你必须在所有实例之间共享一个元表,否则它将无法工作。在这种情况下,您的方法1将不起作用

但是元表不需要是
Dog
,它可以是专用元表:

方法3。
方法/2
如果只定义
函数狗:\uuu eq(rhs)
,则可以正常工作。此方法允许您以相同的方式定义元方法和非元方法。正因为如此,我更喜欢这种方法。@moteus你是对的,但我认为finnw想说的是,比较“类型”相等性的常用方法是检查该对象的元表。如果每个对象都有不同的机器翻译,这种方法就不起作用。不幸的是,他的例子并没有强调这一点。
Dog = {}
local DogMeta = {__index = Dog}
function Dog:new(name)
  local newObj = {sound = 'woof', name = name}
  return setmetatable(newObj, DogMeta)
end
function DogMeta.__eq(dog1, dog2)
  return dog1.name == dog2.name
end