lua的元表以及多继承

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

lua元表

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

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

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

1
2
3
4
5
6
local fathermayun = {
money = 13000000000
}
local me = {}
setmetatable(me, fathermayun)
print(me.money)

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

__index

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

1
2
3
4
5
6
7
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有以下取值

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

继承

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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

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

1
2
3
4
5
6
local Test = class()
function Test:doSomething()
print("test doSomething")
end
local test = Test.new()
test:doSomething()

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

1
2
3
4
5
6
7
local Test = class()
function Test:doSomething()
print("test doSomething")
end
local Test2 = class(Test)
local test = Test2.new()
test:doSomething()

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

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

多继承

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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.
为什么能继承成功?原因如下:

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

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

文章目录
  1. 1. lua元表
  2. 2. __index
  3. 3. 继承
  4. 4. 多继承
|