lua的元表以及多继承

作者: 禹子歆 | 来源:发表于2017-01-07 16:43 被阅读263次

最近做开发的时候,有个类想要继承自多个类,虽然这种情况基本说很少(好像也不少),但还是说一下如何在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脸

相关文章

  • lua的元表以及多继承

    最近做开发的时候,有个类想要继承自多个类,虽然这种情况基本说很少(好像也不少),但还是说一下如何在lua里实现多继...

  • 2018-08-02

    lua实现继承,重载和多态(上) *讲到lua的继承等面向对象的实现,首先得讲一下lua中的几个元方法和元表. s...

  • Lua实现继承

    Lua元表使用 中的__index元方法可以实现面向对象和继承关系: lua中没有类的概念,只有table,但可以...

  • Lua实现继承的方法

    lua通过元表实现继承 lua查找一个表元素的规则如下 1.在表中查找,如果找到,则返回这个元素 2.判断该表是否...

  • 2018-08-06

    lua实现继承,重载和多态(下) 上一篇讲了,lua的几个元方法和元表, 这里我们直接手动实现一个类方法, 可以创...

  • lua实现多继承

    lua对于面向对象的支持主要通过table来实现,每个table都是一个对象,对于继承,lua有元表的机制,通过s...

  • Lua中元表的学习

    Lua本身没有面向对象的思想,但是可以根据表、元表、元方法来靠近它 一、元表与元方法的概念Lua中每个值都可具有元...

  • 【Lua】面向对象解析

    写在前面 我们知道lua本身是不支持继承的,在lua中所有的对象都是由table组成的,这里我们都知道可以使用元表...

  • Lua 实现面向对象 (原创)

    要理解Lua是如何实现面向对象的。首先要熟悉Lua元表的相关知识,可以阅读我上一篇文章《Lua元表 (Metata...

  • Lua 元表(Metatable)

    学习网站Lua 元表(Metatable)

网友评论

    本文标题:lua的元表以及多继承

    本文链接:https://www.haomeiwen.com/subject/onufbttx.html