元方法和类



我创建了一个与此处所示类似的函数,但在__add元方法方面遇到了问题。我希望能够在一个类的两个实例上使用__add元方法,但唯一可行的方法似乎是将元方法添加到实例的元表中。有没有一种方法可以将其设置为工作,这样我的类或其元表就可以使用__add元方法,并在一起添加实例时工作?

function Class(superClass, constructor)
    local class = {};
    local metatable = {};
    if superClass then
        metatable.__index = superClass;
    end
    setmetatable(class, metatable);
    function metatable:__call(...)
        local instance = {};
        setmetatable(instance, { __index = class });
        if class.constructor then
            class.constructor(instance, ...);
        end
        return instance;
    end
    class.constructor = constructor;
    return class;
end

下面是我想做的一个例子:

A = Class(nil, function(self, num)
    self.num = num;
end);
function A:__add(rhs)
    return A(self.num + rhs.num);
end
a = A(1);
b = A(2);
c = a + b;

多亏了三十二上校和埃坦·雷斯纳的帮助,我想出了以下解决方案:

function metatable.__call(self, ...)
    local instance = {};
    setmetatable(instance, self);
    if class.constructor then
        class.constructor(instance, ...);
    end
    return instance;
end

我更改了函数,使其不再隐藏自变量,并将其用作实例的元表。添加现在可以按预期工作。然而,它在其他地方引发了问题。

我尝试了一些在其他地方找到的东西,并提出了这个可行的解决方案:

function Class(superClass, constructor)
    local class = {};
    if superClass then
        for k,v in pairs(superClass) 
        do
            class[k] = v;
        end
        class._superClass = superClass;
    end
    class.__index = class;
    local metatable = {};
    function metatable:__call(...)
        local instance = {};
        setmetatable(instance, class);
        if class.constructor then
            class.constructor(instance, ...);
        end
        return instance;
    end
    class.constructor = constructor;
    setmetatable(class, metatable);
    return class;
end

为了以防万一,我通常是这样创建类的(也很容易支持继承):

function Vector(x, y)
  local self = {}
  self.x = x
  self.y = y
  self.magnitude = math.sqrt(x*x + y*y)
  function self.unit()
    return Vector(x/self.magnitude, y/self.magnitude)
  end
  function self.printComponents()
    print("[" .. self.x .. ", " .. self.y .. "]")
  end
  --if you want to implement metamethods...
  setmetatable(self, {
    __add = function(_, other)
      return Vector(self.x + other.x, self.y + other.y)
    end
  })
  return self
end
-- now, let's make a ComplexNumber class that inherits from Vector
function ComplexNumber(a, b)
  -- define self as an instance of Vector
  local self = Vector(a, b)
  -- override Vector.printComponents()
  function self.printComponents()
    print(self.x .. " + " .. self.y .. "i")
  end
  return self
end
--examples
local v = Vector(10, 20)
v.printComponents() --> [10, 20]
local c = ComplexNumber(10, 5)
c.printComponents() --> 10 + 5i

相关内容

最新更新