在 Lua 中实现类似于 Swift Extension 的机制

本文目标

本文在 Lua 中实现类似于 Swift Extension 的机制,使得在不改变类继承关系、不进行重复代码实现的前提下,实现一些函数的复用。主要作用是减少代码重复。主要思路是在运行时将作为 extensionClass 的表的元素依次拷贝到目标类中。

软件版本

  • Lua 5.1.5

代码

遍历扩展类/表,将其中的对象依次拷贝到目标类中。具体实现如下:

1
2
3
4
5
6
7
8
function extendClass(extensionDestinationClass, extensionSourceClass)
for k, v in pairs(extensionSourceClass) do
if extensionDestinationClass[k] ~= nil then
print("key "..k.." overriden by extension class")
end
extensionDestinationClass[k] = v
end
end

说明

该实现对 number 是按值拷贝,对 string(按 Lua 实现机制,本身就是存储的引用), function, table 是按引用拷贝。

相对于 Swift 的 extension 语法,因为此处 extension 类在定义时不需要指明是对哪个类的扩展,所以一次定义后可用于多种不同的类。而 Swift 则一个 extension 定义对应一个特定的实现,在这一点上本实现略有优势。

使用示例

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
testClass = {}

extensionClass = {}
function extensionClass:ExtendedPrint()
print("hello a extended print")
end

extensionClass.testValue = 20


-- 由于搜索的复杂性,多重继承的效率比起单继承
-- 要低。一个简单的改善性能的方法是将继承方法拷贝到子类。

baseClass = {}
function baseClass:BasePrint()
print("hello this is base print")
end


setmetatable(testClass, {__index = baseClass})
testClass:BasePrint()
--testClass:ExtendedPrint()

--setmetatable(testClass, {__index = extensionClass})


extendClass(testClass, extensionClass)
testClass:BasePrint()
testClass:ExtendedPrint()
print(extensionClass)
print(testClass)
extendClass(testClass, extensionClass)
testClass.testValue = 50

testClass2 = {}
extendClass(testClass2, extensionClass)
print(testClass.testValue)
print(testClass2.testValue)

配合 debugPrint模块 可以得到以下输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@test.lua(38,1) hello this is base print 
@test.lua(38,1) hello this is base print
@test.lua(27,1) hello a extended print
@test.lua(52,1)
{
testValue = 20,
ExtendedPrint = "function: 01044A18"
}
@test.lua(53,1)
{
ExtendedPrint = "function: 01044A18",
testValue = 20
}
@test.lua(10,1) key testValue overriden by extension class
@test.lua(10,1) key ExtendedPrint overriden by extension class
@test.lua(59,1) 50
@test.lua(60,1) 20

可见,testClass 与 testClass2 分别拥有不同的 testValue 实例。但是共用 ExtendedPrint 这个 function 的引用。

示例工程

参考资料