Lua - 理解面向对象编程困难

我在理解 Lua 中的面向对象编程时遇到了很大的困难。根据《Programming in Lua》的说法,我可以像下面这样简单地创建类:

Class = {}

function Class:new()
  setmetatable({}, self)
  self.__index = self

  self.a = 1

  return self
end

function Class:incr()
  self.a = 2 * self.a
  return self
end

但是,当我创建一个实例时,它并不像我期望的那样工作:

-- 正常工作
instance = Class:new()
instance:incr()
print(instance) --> table 0x(address)
print(instance.a) --> 2

-- 然后就变得奇怪了
other = Class:new()
other:incr():incr()
print(other) --> table 0x(same address)
print(other.a) --> 4

print(instance.a) --> 4

我做错了什么?

点赞
用户3574628
用户3574628

PiL 中的示例令人迷惑。它描述了所谓的原型继承。这意味着类和对象之间没有区别。这是一个更加准确的 new 方法版本:

function Class:new()
  -- 注意这里的 self 指代类。我们必须返回一个新对象。
  self.__index = self
  local o = {a=1}
  setmetatable(o, self)
  return o
end

但是我们仍然有一个问题:由于我们的构造方法设置了一个实例变量,所以我们不能用它来创建子类。如果我们尝试这样做,这些子类将在它们自己内部设置 a,而不是在它们的实例中。我们可以定义一个 init 方法,每次创建一个新实例时都要调用它,但这会很麻烦。这里是一种将类和对象分开的可能的方法:

-- 确保每个类都有一个指向自身的 __index。这样它可以成为实例和子类的元表。
local Class = {}
Class.__index = Class

function Class:new()
  local o = {a=1}
  setmetatable(o, self)
  return o
end

function Class:incr()
  self.a = 2 * self.a
  return self
end

-- 要继承,只需将 Class 用作元表。
local Subclass = {}
Subclass.__index = Subclass
setmetatable(Subclass, Class)

这样,new 只用于创建实例。

2018-10-05 22:56:38
用户5525442
用户5525442
function Class:new()
...
   return self -- self 即为 Class = {}
end

other    = Class:new() -- 当你调用 new() 时,other 会得到 Class = {}
instance = Class:new() -- 这里也一样
print(other)    -- 将会打印出 Class = {}
print(instance) -- 将会打印出 Class = {}
2018-10-06 06:28:43