Lua实现类class(搬运)

function class(...)
    -- 返回的表类似“类”的定义
    local cls = {}
    -- 数据都存储在这里面,用作数据存储空间
    local data = {}

    -- 复制传入...的的成员。传入的...类似类定义中的成员列表。需要将父类,以及...内的成员都复制过来
    local function copyField(src, dest)
        -- 先复制父类
        if src['__super'] then
            local superMeta = getmetatable(src['__super'])
            if superMeta and superMeta['__data'] then
                for k, v in pairs(superMeta['__data']) do
                    dest[k] = v
                end
            end
        end
        -- 再复制子类,如果有重名,子类会覆盖父类
        for k, v in pairs(src) do
            if k ~= '__super' then
                dest[k] = v
            end
        end
    end
    copyField(..., data)

    -- lua 5.1之后的版本没有setfenv,引入这段代码解决setfenv问题
    if not setfenv then -- Lua 5.2
        -- based on http://lua-users.org/lists/lua-l/2010-06/msg00314.html
        -- this assumes f is a function
        local function findenv(f)
            local level = 1
            repeat
                local name, value = debug.getupvalue(f, level)
                if name == '_ENV' then
                    return level, value
                end
                level = level + 1
            until name == nil
            return nil
        end
        getfenv = function(f)
            return (select(2, findenv(f)) or _G)
        end
        setfenv = function(f, t)
            local level = findenv(f)
            if level then
                debug.setupvalue(f, level, t)
            end
            return f
        end
    end

    -- 设置cls的元表
    setmetatable(
        cls,
        {
            -- 数据存储空间
            __data = data,
            -- __newindex处理赋值时的相关逻辑,类似set
            __newindex = function(t, key, newValue)
                local oldValue = data[key]
                -- 根据旧值的类型,判断新值的类型是否相同,不相同打印提示,相同才赋值
                if oldValue then
                    if type(oldValue) == 'function' then
                        print('函数不能赋值')
                        return
                    else
                        if type(newValue) ~= type(data[key]) then
                            print('类型不匹配:', tostring(key), ' 的类型是', type(data[key]))
                            return
                        end
                    end
                end

                -- 将新值赋值
                data[key] = newValue
            end,
            -- __index处理获取值时的相关逻辑,类似get
            __index = function(t, key)
                if data[key] then
                    local value = data[key]
                    --[["
                    下面代码主要处理的是:A和B的foo函数体中都没有使用self,此时就得从全局表中获取该变量的值
                        foo = function()
                            print('from A', name, age)
                        end
                    "]]
                    if type(value) == 'function' then
                        -- 新建一个全局表
                        local newG = {}
                        setmetatable(newG, {__index = _G})
                        -- 将数据赋值到全局表中
                        for k, v in pairs(data) do
                            if type(v) ~= 'function' then
                                newG[k] = v
                            end
                        end
                        -- 设置函数的全局环境表
                        setfenv(value, newG)
                    end

                    -- 返回原始值
                    return value
                end
                return nil
            end,
            -- __call可以使class创建的对象被调用,类似构造函数的用法,调用后复制出来一个实例
            __call = function()
                local instance = {}
                setmetatable(instance, getmetatable(cls))
                return instance
            end
        }
    )
    return cls
end

--实现 class 方法
A =
    class {
    name = '',
    age = 0,
    foo = function()
        print('from A', name, age)
    end
}

B =
    class {
    __super = A,
    foo = function()
        print('from B', name, age)
    end
}

local a = A()
a.name = 'hanmeimei'
a.age = 17
a:foo()

local b = B()
b.name = 'lilei'
b.age = 18
b:foo()

a.name = 20
a.age = '20'
b.foo = 'x'

原帖地址

https://blog.csdn.net/zhenghongzhi6/article/details/99084309?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-1.control&spm=1001.2101.3001.4242

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Lua 中,我们可以通过创建一个表(table)来表示一个,然后通过给这个表设置元方法(metamethod)来实现面向对象编程的特性。要实例化一个,我们可以使用以下两种方式之一: 1. 使用字面量表达式创建对象实例 与上面创建对象实例的方式似,我们也可以使用字面量表达式来创建一个对象实例。不同的是,这个表的元表(metatable)需要设置为表(class table),以便对象可以继承的属性和方法。 例如,我们可以创建一个Person,代码如下: ``` local Person = {name = "default", age = 0} function Person:new(name, age) local obj = {name = name, age = age} setmetatable(obj, self) self.__index = self return obj end function Person:sayHello() print("Hello, my name is " .. self.name .. ", I'm " .. self.age .. " years old.") end ``` 在上面的代码中,我们定义了一个Person,其中包括两个属性name和age,以及两个方法new和sayHello。其中,new方法用于创建新的Person对象实例,sayHello方法用于输出Person对象的信息。 要实例化一个Person,我们可以像下面这样创建一个对象实例: ``` local person = {name = "Tom", age = 20} setmetatable(person, Person) ``` 在上面的代码中,我们使用一个字面量表达式创建了一个表,其中包含了name和age两个属性,并给它们分别赋了初值。然后我们使用setmetatable函数将这个表的元表设置为Person,这样这个表就可以继承Person的属性和方法了。这个表就可以看作是一个Person对象实例了。 2. 使用的构造函数创建对象实例 与上面实例化对象的方式似,我们也可以在中定义一个构造函数,用于创建新的对象实例。在构造函数中,我们可以使用的元表(metatable)来初始化新的对象实例。 例如,我们可以重新定义Person的构造函数,代码如下: ``` local Person = {name = "default", age = 0} function Person:new(name, age) local obj = {name = name, age = age} setmetatable(obj, self) self.__index = self return obj end function Person:sayHello() print("Hello, my name is " .. self.name .. ", I'm " .. self.age .. " years old.") end ``` 在上面的代码中,我们重新定义了Person的构造函数new,使用的元表来初始化新的对象实例。要实例化一个Person,我们可以像下面这样使用构造函数来创建一个对象实例: ``` local person = Person:new("Tom", 20) ``` 在上面的代码中,我们调用Person:new("Tom", 20)来创建一个新的Person对象实例。这个person就可以看作是一个Person对象实例了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值