有人在问如何实现Lua中的多重继承。真正用到多重继承的时候,我会想想是不是非得用多重继承,总觉得多重继承有点“重”。
多重继承例子
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
local function search(k, tables)
for i, v in ipairs(tables) do
if v[k] then
return v[k]
end
end
return nil
end
-- 这里实现多重继承,参数arg为多重父类表
function createClassFrom(...)
-- c为返回值的目标表,为实现多重继承的子类表
local c = {}
local parents = {...}
setmetatable(c, {__index = function(t, k)
return search(k, parents)
end})
function c: new (o)
o = o or {}
setmetatable(o, {__index = c})
return o
end
return c
end
-- 人 吃饭
Human = {name = "human" }
function Human:eat()
print( "human eat" )
end
-- 程序员 写代码
Programmer = {name = "coder" }
function Programmer:doProgramming()
print( "do coding" )
end
-- 女程序员 继承 人和程序员
-- 性别女
FemaleProgrammer = createClassFrom(Human, Programmer)
local femaleCoder = FemaleProgrammer: new ({sex = "female" , canBear = function() print( "Female: can give birth a baby!" ) end})
femaleCoder:eat() -- human eat
femaleCoder:doProgramming() -- do coding
|
上面代码难点在于理解lua中__index的用法。我们在lua中实现继承的时候,会用到这个__index。我们再次看看这个__index究竟是怎么回事。元表的__index可以是一个表,也可以是一个函数。
1. __index是个表的情况
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
local Test = { group = "quick" }
function Test: new (o)
o = o or {}
setmetatable(o, {__index = Test})
return o
end
function Test:getName()
return self.name
end
function Test:setName(name)
self.name = name
end
local a = Test: new ({name = "Just a test" })
print(a:getName()) -- Just a test
print(a.group) -- quick
|
当表a调用自身所没有的方法( getName() )或者属性(group)的时候, Lua会通过getmetatable(a)得到a的元表{index = Test}, 而该元表的`index`是个表Test,则Lua会在这个表Test中看看是否有缺少的域方法("getName")以及属性(group),如果找到了则会调用表Test的方法或者属性。
2. __index 是函数的情况
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
local Test = { }
Test.prototype = { group = "quick" ,
qq = "284148017" ,
company = "chukong" ,
getName = function() return "Just a test" end}
function Test: new (o)
o = o or {}
setmetatable(o, {__index = function(table, key)
return Test.prototype[key]
end})
return o
end
local a = Test: new ()
print(a:getName()) -- Just a test
print(a.qq) -- 284148017
print(a.company) -- chukong
|
当表a调用自身所没有的方法(getName)或者属性(qq/company)的时候, lua会通过getmetatable(a)得到a的元表 {__index = function(table, key) return Test.prototype[key] end}, 而该元表的__index是个函数,该函数的实参依次为正在调用方法、属性的表a以及表a中缺失的方法名或属性(键值key),lua会将这两个实参传入进去并调用__index指向的函数。
例如:
- a:getName()时,就会调用a的元表的__index方法,将自身a以及"getName"键名依次传入进去,返回了Test.prototype["getName"]该函数,lua会自动调用该函数,所以a:getName()会返回Just a test。
- a.qq时,就会调用a的元表的__index方法,将自身a以及"qq"键名依次传入进去,返回了Test.prototype["qq"]即284148017。
相关阅读
|
请发表评论