在Lua中为新对象指定元表

时间:2013-12-13 02:13:31

标签: 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)
end

我见过大多数人都使用 self.__index = self 方法,这对我来说似乎很笨拙。为什么要将整个Dog对象与所有不构成metatable的其他方法传递给setmetatable方法/ 1 适用于将新对象的metatable.__index设置为Dog对象,它也更清晰。

是否有充分的理由使用方法/ 2 而不是方法/ 1


提供上下文的一些附加代码,它适用于两种方法

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

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

3 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

虽然两种方法都达到了相同的最终行为,但有人可能更喜欢方法2,因为它更符合“创建循环资源”策略。无论您创建多少狗对象,方法2将始终使用一个表Dog作为元表。方法1,OTOH,将创建一个新的匿名表,只是作为创建的每个Dog对象的元。

然而,方法1可能更容易阅读和推理该语言的新手,因为它没有将metatables和对象定义的关注混合在一起。

答案 2 :(得分:1)

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

但是metatable不需要是Dog,它可以是一个专用的metatable:

方法3。

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