Lua使用table来面向对象。
一个简单的 Account 类:
Account = {balance = 0}
function Account.sub(self, v)
self.balance = self.balance - v
end
a = Account
a.sub(a, 10)
print(a.balance)
这里还有一种更简介表示方法:
Account = {balance = 0}
function Account:sub(v) --使用冒号
self.balance = self.balance - v
end
a = Account
a:sub(10) --使用冒号
print(a.balance)
这里的冒号是Lua的一种语法糖。
类:
local Account = {}
--[=[
Account = {
value,
}
--]=]
function Account:new(account)
account = account or {}
setmetatable(account, self)
self.__index = self
return account
end
function Account:display()
print(self.value)
end
local account = Account:new({value = 10})
account:display() --相当于Account.display(account)
这里通过 Account:new 得到的 account 的元表为 Account,且具有 __index = Account。这样当 account:display() 时,虽然 account 并没有 display() 函数,但会调用其元表的 __index 字段里的 display() 函数。这里如果将
setmetatable(account, self)
self.__index = self
换成
setmetatable(account, {__index = self})
同样可以达到目的。
实例对象account中并没有display方法,而是继承自Account的方法,而且传入display方法中的self却是account。这样就可以让Account(这个“类”)定义操作。除了方法,account还能从Account继承所有的字段。如下:
local Account = {value = 20}
--[=[
Account = {
value,
}
--]=]
function Account:new(account)
account = account or {}
setmetatable(account, self)
self.__index = self
return account
end
function Account:display()
self.value = self.value + 100
print(self.value)
end
local account = Account:new{}
account:display()
account:display()
print(Account.value)
输出结果为:
120
220
20
account 第一次调用 display() 时,等号左边的 self.value 就是 account.value,而右边的 self.value 则使用了 Account.value。第二次调用时 account.value 字段已有。
继承:
上面的例子其实已经有了继承,account 继承自 Account。这里我们在进一步介绍下:
local Person = {sex = "male"}
function Person:new(person)
person = person or {}
setmetatable(person, self)
self.__index = self
return person
end
function Person:display()
print(self.sex)
end
local Son = Person:new{}
Son:display()
local Grand = Son:new{sex = "female"}
Grand:display()
这个例子中,Son 继承自 Person,之后 Grand 继承自 Son。当执行Grand:display() 时,Lua在Grand中找不到display字段,就会查找Son;如果仍然找不到display字段,就查找Person,最终会在Person中找到display字段。可以这样想一下,如果在Grand中存在了display字段,那么就不会去Person中再找了。所以,我们就可以在Grand中重定义display字段,从而实现特殊版本的display函数。继承的实现依靠了元表 __index 字段的逐层指向。Son 元表的 __index 指向 Person, Grand 元表的 __index 指向 Son。