代码之家  ›  专栏  ›  技术社区  ›  aurora

Lua中元方法的继承

  •  6
  • aurora  · 技术社区  · 15 年前

    我非常喜欢“在Lua中编程”16.1、16.2中如何描述面向对象编程:

    http://www.lua.org/pil/16.1.html

    http://www.lua.org/pil/16.2.html

    希望遵循这种方法。但我想做得更进一步:我想要一个名为“class”的“class”基础,它应该是所有子类的基础,因为我想在那里实现一些助手方法(如“instanceof”等),但本质上应该如书中所述:

    function class:new(o)
        o = o or {}
        setmetatable(o, self)
        self.__index = self
        return o
    end
    

    现在我的问题是:

    我想要一个从“class”继承的类“number”:

    number = class:new()
    

    我想为这个类中的运算符重载(uu add,u sub,等等)定义元方法,比如:

    n1 = number:new()
    n2 = number:new()
    
    print(n1 + n2)
    

    作品。这真的不是问题。但是现在我想要一个三等的“钱”,它继承自“数字”。

    money = number:new{value=10,currency='EUR'}
    

    我在这里等等介绍一些新特性。

    现在我的问题是,我不能让事情正常运转,“钱”继承了“类”和“数字”的所有方法 包括 “数字”中定义的所有元方法。

    我尝试过一些方法,例如重写“new”或修改元表,但是我无法使事情正常工作,要么在“money”中失去“class”方法,要么在“money”中失去“number”的元方法。

    我知道,有很多类实现,但是我真的很想坚持使用Lua本身的最小方法。

    任何帮助都将非常感谢!

    非常感谢!

    3 回复  |  直到 15 年前
        1
  •  3
  •   gwell    15 年前

    rawget(getmetatable(obj) or {}, "__add")

    new

    function class:new(o)
        o = o or {}
        setmetatable(o, self)
        self.__index = self
        local m=getmetatable(self)
        if m then
            for k,v in pairs(m) do
                if not rawget(self,k) and k:match("^__") then
                    self[k] = m[k]
                end
            end
        end
        return o
    end
    
        2
  •  2
  •   kikito    15 年前

    middleclass

    local _metamethods = { -- all metamethods except __index
      '__add', '__call', '__concat', '__div', '__le', '__lt', '__mod', '__mul', '__pow', '__sub', '__tostring', '__unm'
    } 
    

    -- creates a subclass
    function Object.subclass(theClass, name)
      ...
    
      local dict = theSubClass.__classDict -- classDict contains all the [meta]methods of the 
      local superDict = theSuperClass.__classDict -- same for the superclass
      ...
    
      for _,mmName in ipairs(_metamethods) do -- Creates the initial metamethods
        dict[mmName]= function(...) -- by default, they just 'look up' for an implememtation
          local method = superDict[mmName] -- and if none found, they throw an error
          assert( type(method)=='function', tostring(theSubClass) .. " doesn't implement metamethod '" .. mmName .. "'" )
          return method(...)
        end
      end 
    

    __len

    __index __newindex

        3
  •  0
  •   Jonathan Swinney    15 年前

    RootObjectType = {}
    RootObjectType.__index = RootObjectType
    function RootObjectType.new( o )
            o = o or {}
            setmetatable( o, RootObjectType )
            o.myOid = RootObjectType.next_oid()
            return o
    end
    
    function RootObjectType.newSubclass()
            local o = {}
            o.__index = o
            setmetatable( o, RootObjectType )
            RootObjectType.copyDownMetaMethods( o, RootObjectType )
            o.baseClass = RootObjectType
            return o
    end
    
    function RootObjectType.copyDownMetaMethods( destination, source ) -- this is the code you want
            destination.__lt = source.__lt
            destination.__le = source.__le
            destination.__eq = source.__eq
            destination.__tostring = source.__tostring
    end
    
    RootObjectType.myNextOid = 0
    function RootObjectType.next_oid()
            local id = RootObjectType.myNextOid
            RootObjectType.myNextOid = RootObjectType.myNextOid + 1
            return id
    end
    
    function RootObjectType:instanceOf( parentObjectType )
            if parentObjectType == nil then return nil end
            local obj = self
            --while true do
            do
                    local mt = getmetatable( obj )
                    if mt == parentObjectType then
                            return self
                    elseif mt == nil then
                            return nil
                    elseif mt == obj then
                            return nil
                    else
                            obj = mt
                    end
            end
            return nil
    end
    
    
    function RootObjectType:__lt( rhs )
            return self.myOid < rhs.myOid
    end
    
    function RootObjectType:__eq( rhs )
            return self.myOid == rhs.myOid
    end
    
    function RootObjectType:__le( rhs )
            return self.myOid <= rhs.myOid
    end
    
    function RootObjectType.assertIdentity( obj, base_type )
            if obj == nil or obj.instanceOf == nil or not obj:instanceOf( base_type ) then
                    error( "Identity of object was not valid" )
            end
            return obj
    end
    
    function set_iterator( set )
            local it, state, start = pairs( set )
            return function(...) 
                    local v = it(...)
                    return v
            end, state, start
    end