Lua怎么实现面对对象
Lua中的table就是一种对象
- table和对象一样可以拥有状态
- table和对象一样拥有一个独立于其值的标识(一个self): Lua只需要使用冒号,则能隐藏该self参数
- able和对象一样具有独立于创建者和创建地的生命周期
local table1 = {a = 1, b = 2}
local table2 = {a = 1, b = 2}
print(table1 == table2) -- return false
原理:lua面向对象编程是基于元表metatable,元方法__index来实现的
lua中的函数默认都是有self传递进去的,self相当于C++类中函数的this指针,语法糖会自动给我们传递 self
local a = {
x = 1
}
function a:print()
print("function!"..self.x)
end
a.print(a)
a:print()
面对对象原理(metatable元表 + _index原方法)
解释:元表像是一个备用查找表,假设表A的元表是B,那么在A中找不到的东西就会尝试在B中去找,设置元表的函数如下 setmetatable(A, B),这样表B就被设置为A的元表,当A中查找不到某个变量时就会到B中进行查找
A = {}
B = {a = 1}
-- must assign B to _index
B._index = B
-- set B as metatable of A
setmetatable(A, B)
-- can get variable that A doesn't contain but B contain
print(A.a)
面对对象的封装
主要还是用table做类,新建对象用metatable和基对象做联系
Class = {
x = 1,
y = 2
}
Class._index = Class
-- same as constructure
function Class:new(x, y)
-- create a new object, so that the instance is independent
local tempObj = {}
tempObj.x = x
tempObj.y = y
-- set the metatable for the new object
setmetatable(tempObj, Class)
-- return the object
return tempObj
end
function Class:add(val)
self.x = x + val
self.y = y + val
end
-- Test Code
local Obj = Class:new(1, 2)
Obj.add(2)
print(Obj.x, Obj.y) -- print 3, 4
面对对象的继承和多态
-- SubClass that extends Class
SubClass = {
z = 0
}
setmetatable(SubClass, Class)
SubClass._index = SubClass
-- constructure function
function SubClass:new(x, y, z)
-- call base class first
local tempObj = Class:new(x, y)
-- set SubClass as metatable not Class!
setmetatable(tempObj, SubClass)
-- assign value to z of SubClass
tempObj.z = z
return tempObj
end
-- override the Add() from Class
function SubClass:Add(val)
self.x = self.x + val * 2
self.y = self.y + val * 2
end
-- test code
local Obj = Class:new(1, 2)
Obj:Add(5) -- x = 6, y = 7
local SubObj = SubClass:new(1,2,3)
SubObj:Add(5) -- x = 11, y = 12, z = 3
封闭私密性
思路:通过两个table来表示一个对象。一个table用来保存对象的私有数据;另一个用于对象的操作。对象的实际操作时通过第二个table来实现的。为了避免未授权的访问,保存对象的私有数据的表不保存在其它的table中,而只是保存在方法的closure中
function new(defaultName)
local self = {name = defaultName} -- keep variable in table
local setName = function (v) self.name = v end
local getName = function () return self.name end
return {setName = setName, getName = getName} -- only return method 只能通过newObject中创建的函数来访问这个self table
end
local object= new("aaa")
object.setName("aaa") -- 不需要多余的self字段的,也就不用冒号了。
print(object.getName()) -- print aaa
Lua的闭包
一个closure就是一种可以访问其外部嵌套环境中的局部变量的函数。对于closure而言,这些变量就可用于在成功调用之间保持状态值,从而使closure可以记住它在一次遍历中所在的位置。
一个closure结构通常涉及到两个部分:closure本身 + 一个用于创建closure的工厂函数
迭代器是最经典的闭包:
for word in allwords() then
print(word)
end
function allwords()
local line = io.read() -- current line
local pos = 1 -- current position of the line
return function() -- iterate function 工厂函数
while line do -- enter loop if the line is valid
local s, e = string.find(line, "%w+", pos)
if s then -- if there is next word
pos = e+1 -- the next word
return string.sub(line, s, e) -- return the word
else
line = io.read() -- find other line if there is no word
pos = 1; -- restart from the first position
end
end
return nil -- there is no word anymore
end
end
关于
upvalue,他的实质其实是局部变量,而局部变量是保存在函数堆栈框架上的。所以只要upvalue还没有离开自己的作用域,他就一直生存在函数堆栈上。这种情况下,闭包将通过指向堆栈上的upvalue的引用来访问他们,一旦upvalue即将离开自己的作用域(这也意味着他马上要从堆栈中消失),闭包就会为他分配空间并保存当前的值,以后便可通过指向新分配空间的引用来访问该upvalue举例:
function f1(n)
local function f2()
print(n)
end
n = n + 10
return f2
end
g1 = f1(10)
g1() -- 20
当执行到f1(10)的 n = n + 10时,闭包已创建了,不过n并没有离开作用域,所以闭包仍然引用堆栈上的n,、
当return f2完成时,n即将结束生命,此时闭包便将n(已是20了)复制到自己管理的空间中以便将来访问。
Reference:
- https://blog.csdn.net/yzf279533105/article/details/80099358
- https://www.jianshu.com/p/467840d7ad13
- https://blog.csdn.net/liu943367080/article/details/88951964

浙公网安备 33010602011771号