2

方法/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为什么要使用不构成元表的所有附加方法传递整个对象setmetatableMethod/1适合将新对象设置为metatable.__index对象Dog,它也更干净。

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


一些额外的代码来提供上下文,它适用于这两种方法

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

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

3 回答 3

1

Method/2Method/1更优化一点,因为它不需要创建额外的表作为它的元表。它使用自己作为元表。

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

于 2013-12-13T02:37:27.760 回答
1

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

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

于 2013-12-13T02:38:54.493 回答
1

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

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

方法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
于 2013-12-13T04:52:58.403 回答