lua的元表以及多继承

最近做开发的时候,有个类想要继承自多个类,虽然这种情况基本说很少(好像也不少),但还是说一下如何在lua里实现多继承。
其实很简单,首先要了解lua元表,以及lua类的实现方法。

lua元表

用lua的人都知道lua的table的强大,table有一套hashmap的查找机制,如果访问一个表中并不存在的字段,不会立即返回nil,而是先触发一套查找机制,也是我们用以实现面向对象的方法
简单的描述:元表就是用于查找的备用表。
比如:

local me = {}
print(me.money) -- me中没有money字段,所以打印出来的会是nil

这里的执行结果很明显会是nil,没有疑问(因为我是个穷逼。
但是如果我设置了元表:

local fathermayun = {
    money = 13000000000
}
local me = {}
setmetatable(me, fathermayun)
print(me.money)

这里的执行结果是!!!!!!!
nil
为什么我没有拿到马云爸爸的钱?因为没有设置__index

__index

简单的描述:是当table中一个元素不存在的时候,会触发寻找元表的__index元方法,如果不存在,则返回nil,如果存在,则返回结果。
所以,把上述代码改成

local fathermayun = {
    money = 13000000000
}
fathermayun.__index = fathermayun
local me = {}
setmetatable(me, fathermayun)
print(me.money)

这里的执行结果将是13000000000,我终于有钱了:)
上面的执行过程是:
访问me.money->发现没有这个字段->me有元表->查找元表fathermayun->lua不会直接找fathermayun里的money字段->lua发现fathermayun有元方法__index->调用元方法->发现元方法是个table,在元方法的table里寻找->获得money的值
__index有以下取值

表,会直接在表里找
函数,返回函数的返回值

继承

利用上述知识随手写了个实现面向对象的方法,不是很完善

local function class(super)
    local cls
    if super then
        cls = {}
        cls.super = super
        setmetatable(cls, {__index = super})
    else
        -- ctor是构造函数的命名
        cls = {ctor = function () end}
    end

    cls.__index = cls
    function cls.new(...)
        local instance = setmetatable({}, cls)
        instance:ctor(...)
        return instance
    end
    return cls
end

挺简单的,注释就不写了……让我们来测试一下

local Test = class()
function Test:doSomething()
    print("test doSomething")
end
local test = Test.new()
test:doSomething()

成功打印出”test doSomething”
接下来试试继承

local Test = class()
function Test:doSomething()
    print("test doSomething")
end
local Test2 = class(Test)
local test = Test2.new()
test:doSomething()

也可以成功打印出”test doSomething”,继承成功
为什么能继承成功?原因如下:

在new的时候,创建一个table并返回,即创建一个实例,实例可以有自己的字段,比如Test类的doSomething,该字段是个函数,可以调用执行。实例的元表是cls,如果调用实例没有的字段,会去cls里找
cls设置了元方法__index = cls
如果没有super,则只有一个构造函数方法
如果有super,cls的元表是super,元表的元方法也正确的设置了
所以,在Test2是继承自Test的,它的实例test调用doSomething,找不到,去元表里找,元表发现自己有父类,去父类里找,成功找到。

多继承

如果我想要继承多个父类,怎么办?
其实思路很简单,把元方法改成函数即可。
举例子:

local function search(key, tables)
    for _, super in ipairs(tables) do
        if super[key] then
            return super[key]
        end
    end
    return nil
end

local function class(...)
    local cls = { ctor = function () end}
    local supers = {...}
    setmetatable(cls, {__index = function (_, key)
        -- 在查找table的时候,会把table的key传进来
        return search(key, supers)
    end})
    
    function cls.new(...)
        local instance = {}
        setmetatable(instance, {__index = cls})
        instance:ctor(...)
        return instance
    end
    return cls
end

local Human = class()
function Human:life()
    print("almost 100 years.")
end
local Programmer = class()
function Programmer:coding()
    print("sub 1 year.")
end
local My = class(Human, Programmer)
local yuzixin = My.new()
yuzixin:life()
yuzixin:coding()

成功打印出结果
almost 100 years.
sub 1 year.
为什么能继承成功?原因如下:

在yuzixin里找不到life和coding字段,去找元表cls,调用元方法__index
__index调用函数search,把所有的父类都找一遍
成功找到

多继承就这样成功啦!撒花!
注意写一次代码减少一年的生命哦……(悲伤doge脸

    原文作者:禹子歆
    原文地址: https://www.jianshu.com/p/3eaa69a6d0a2
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞