【问题标题】:Lua OOP. How to inherit tables from a prototype卢亚面向对象。如何从原型继承表
【发布时间】:2020-04-02 11:29:21
【问题描述】:

Lua 中的编程中,我找到了一个使用继承的示例。我了解它是如何通过元表__index 处理的,但是当我制作自己的示例时,其中一个要继承的项目是一个表,我意识到该表是由新创建的对象共享的:

Account = {
    balance = 0,
    info = {},
    withdraw = function (self, v)
        self.balance = self.balance - v
    end,
    deposit = function (self, v)
        self.balance = self.balance + v
    end,
    add = function (self, item)
        if self:check(item) then return end
        table.insert(self.info, item)
    end,
    remove = function (self, item)
        table.remove(self.info, item)
    end,
    check = function (self, item)
        for i, v in ipairs(self.info) do
            if v == item then return true end
        end
    end,
    new = function (self, o)
        o = o or {}
        self.__index = self
        setmetatable(o, self)
        return o
    end,
}

local a1 = Account:new()
local a2 = Account:new()
local a3 = Account:new()


a1:deposit(50)
a1:add("aaa")
a2:deposit(100)
a2:add("bbb")
a2:add("bbb")

print(a1.balance)
for _, v in ipairs(a1.info) do print(v) end
print(a2.balance)
for _, v in ipairs(a2.info) do print(v) end

这里info被所有对象共享:

50
aaa
bbb
100
aaa
bbb

如何使每个新对象中的信息独一无二?

编辑。解决方法是我将所有“字段”放在方法 new 中,同时将方法留在原型中,但我认为它不是很优雅:

    new = function (self, o)
        o = o or {}
        o.balance = 0
        o.info = {}
        self.__index = self
        setmetatable(o, self)
        return o
    end,

谢谢

【问题讨论】:

    标签: lua prototype


    【解决方案1】:

    答案可能比你想象的要容易;您在“类”表中分配info。相反,只需为构造函数中的每个实例分配一个新的info 表:

    function Account:new(instance)
       instance = instance or {}
       instance.info = {}
       setmetatable(instance, self)
       return instance
    end
    

    请注意,在我的示例中,我删除了 self.__index = self 行,因为您不应该在构造函数中这样做。相反,在创建表后将其分配一次为Account.__index=Account

    【讨论】:

    • 示例来自 Programming in Lua ed.4 但我添加了表格info。我认为__index 在元表(此处为帐户)中是必需的,以便新对象instance 找到instance 中缺失键的替代品。 Account 在您的示例中没有 __index。你为什么不需要它?
    • 我在这个答案(__info -> __index)中编辑了看起来像是错字的地方。 @Celdor,这可以为您解释吗?
    • 我明白了。是的,您在答案中解释的内容更清楚。谢谢。现在只有我想知道你的建议和 self.__index=self 在 new 之间有什么区别。我正在学习这些东西,并且可能遗漏了一些东西,但对我来说,new 方法中的 self 拥有 Account 的地址。最后,这两种方法都设置了相同的元表。
    • 不同之处在于何时以及多久设置元表中的值。你真的只需要一次,但你要为每个新实例再做一次 - @luther 确实是一个错字,感谢修复它:D
    • 现在说得通了。谢谢。