方式/ 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
对象,它也更清晰。
提供上下文的一些附加代码,它适用于两种方法
function Dog:makeSound()
print('I say ' .. self.sound)
end
mrDog = Dog:new()
mrDog:makeSound()
答案 0 :(得分:1)
方法/ 2 比方法/ 1 更优化,因为它不需要创建额外的表作为其元表。它将自己用作元表。
既然您说您认为方法/ 1 在您的问题中更清晰,请随意使用它。我不认为两者之间的性能差异在大多数情况下都很重要。可读性几乎总是更重要。
答案 1 :(得分:1)
虽然两种方法都达到了相同的最终行为,但有人可能更喜欢方法2,因为它更符合“创建循环资源”策略。无论您创建多少狗对象,方法2将始终使用一个表Dog
作为元表。方法1,OTOH,将创建一个新的匿名表,只是作为创建的每个Dog对象的元。
然而,方法1可能更容易阅读和推理该语言的新手,因为它没有将metatables和对象定义的关注混合在一起。
答案 2 :(得分:1)
如果你想要一个__eq
元方法,你必须在所有实例之间共享一个metatable,否则它将无效。在这种情况下,您的方法#1将不起作用。
但是metatable不需要是Dog
,它可以是一个专用的metatable:
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