面向对象编程中, 很重要的概念之一是隐含的 “this” 指针, 即有一个变量指代了自身.在 lua 中, 使用 “self” 代表 “this”.
--[[ (1)
基本代码.
--]]
Account = {balance = 0}
function Account.withdraw(v)
Account.balance = Account.balance - v
end
--[[ (2)
使用 (1) 中的 Account.
调用 a.withdraw(100.0) 时, 函数内部应当调用 a.balance = a.balance - 100.0,
而函数定义为 Account.balance = Account.balance - v, 所以出错.
--]]
Account.withdraw(100.0)
print(Account.balance) --> -100
a = Account
a.withdraw(100.0) --> error
--[[ (3)
对 (1) 的改进, 即重写 withdraw() 函数.
这里明确指明了 self 参数, 即调用者.
--]]
Account = {balance = 0}
function Account.withdraw(self, v)
self.balance = self.balance -v
end
--[[ (4)
使用 (3) 中代码.
--]]
a = Account
a.withdraw(a, 100.0)
print(a.balance) --> -100
print
--[[ (5)
在面各对象编程中, "self" 一般是隐含的, 在 Lua 中要隐含 self 指针, 需要另一个':' 语法来定义表中的函数.
--]]
Account = {balance = 0}
function Account:withdraw(v)
self.balance = self.balance -v -- 函数内部可直接使用 self, 表示调用者
end
a = Account
a.withdraw(100.0)
print(a.balance) --> -100
类的定义:
以 C++ 为例. 在工程代码中, 一个类通常定义一个文件中, 数据是私有的,
函数是公共的. 对数据的操作都通过成员函数进行. 在 Lua 中,
将一个类定义在一个文件中, 可以认为 Lua 的类就是一个模块. 下面代码模拟这种 C++
类的定义, 但这种实现无法实现 “继承”.
-- 文件 (模块) 名: account.lua
function new_account(initial_balance)
-- 这里的 self, 可以随便命名. 导出的函数都是操作这个表
local self = {balance = 0}
-- 赋初值
self.balance = initial_balance
-- 可以定义不被外部调用的私有函数
local function inter_call()
end
-- 设置余额
local function set_balance(balance)
self.balance = balance
end
-- 获取余额
local function get_balance()
return self.balance
end
-- 取钱
local function withdraw(v)
self.balance = self.balance - v
end
-- 存钱
local function deposit(v)
self.balance = self.balance + v
end
------ 返回可以被外部调用的函数---------------
return{
set_balance = set_balance,
get_balance = get_balance,
withdraw = withdraw,
deposit = deposit
}
end
调用 “account.lua” 的代码
require "account"
local my_account = new_account(100)
print(my_account.get_balance()) --> 100
my_account.set_balance(200)
print(my_account.get_balance()) --> 200
my_account.withdraw(50)
print(my_account.get_balance()) --> 150
my_account.deposit(100)
print(my_account.get_balance()) --> 250
由上述代码可知, 它仅仅是利用 Lambda 的特性模拟了 “类” 的实现.
其中一个本质性特点是, 数据与方法分离.
利用元表, 可以实现 “类” 的 “继承”.
-- 基类 -----------------
Account = {balance = 0}
-- 必须调用此函数得到一个对象, 才能保证对象是从 Account 继承而来
function Account:new_class()
local o = {}
self.__index = self
setmetatable(o, self)
return o
end
--
function Account:get_balance()
return self.balance
end
--
function Account:depoist(v)
self.balance = self.balance + v
end
--
function Account:withdraw(v)
self.balance = self.balance -v
end
-- 派生类 ---------------------------
SpecialAccount = Account:new_class()
-- 扩充子类
SpecialAccount.user = "anonymous"
function SpecialAccount:set_user(user)
self.user = user
end
function SpecialAccount:get_user()
return self.user
end
-- 使用 -----------------------------
my_account = SpecialAccount:new_class()
print(my_account:get_user()) --> anonymous
my_account:set_user("dzf")
print(my_account:get_user()) --> dzf
-- 操作父类的方法
my_account:depoist(500)
print(my_account:get_balance()) --> 500
上述代码中, “类” 的成员变量是公有的, 方法也是私有的.
其中一个本质性特点是数据与方法不分离.
若要将上述两者结合起来, 即实现数据为私有, 方法为私有,
同时数据和方法都可以被继承, 可以使用对偶表的方式实现.
其核心是表的每个域都用一个表来实现.
-- 基类 ------------------------------------------------------------------
Account = {}
-- 账户拥有两个属性: 用户及余额. 用表来实现这两个属性. 事实上, 所有的账户,
-- 基类及子类所有的用户和余额字段都存在同一个表中.
-- 这些域为 local, 外部不可访问, 从而实现数据的私有性.
local balance_field = {}
balance_field[Account] = 0
local user_field = {}
user_field[Account] = "anonymous"
-- 由于数据已经私有, 那么方法就可以定义为 "类" 的方法
function Account:set_user(user)
user_field[self] = user
end
function Account:get_user()
return user_field[self]
end
function Account:get_balance()
return balance_field[self]
end
function Account:witdraw(v)
balance_field[self] = balance_field[self] - v
end
function Account:deposit(v)
balance_field[self] = balance_field[self] + v
end
function Account:new()
local o = {}
setmetatable(o, self)
self.__index = self
self.__mode = "k" -- 一定要让键为弱引用, 否则不会被回收
-- 初值
balance_field[o] = 0
user_field[o] = "anonymous"
return o
end
-- 派生类 -------------------------------------------
SpecialAccount = Account:new()
--派生类扩展的域
local site_field = {}
site_field[SpecialAccount] = "none"
function SpecialAccount:get_site()
return site_field[self]
end
function SpecialAccount:set_site(site)
site_field[self] = site
end
-- 测试代码 ----------------------------------------
local myAccount = SpecialAccount:new()
m = myAccount
print(SpecialAccount:get_site()) --> none
print(m:get_balance()) --> 0
m:deposit(500)
print(m:get_balance()) --> 500
print(m:get_site()) --> nil
m:set_site("beijing")
print(m:get_site()) --> beijing