Lua面向对象编程
来源:互联网 发布:直男癌语录知乎 编辑:程序博客网 时间:2024/05/18 17:01
概述
Lua中的table本身就是一种对象
- table和对象一样可以拥有状态、属性,以及对这些状态和属性的操作
- table和对象一样拥有独立其值的标志(self)
- table和对象一样具有独立于创建者的生命周期,换句话说,就是自己掌握自己的生命周期
但是,和C++、Java语言不一样,它并不存在显示的关键词(例如,Class)来描述一个类,所以我们只能利用table和元表机制来模拟类
Lua的面向对象是建立在元表和元方法这一机制上的,应当清楚的明白Lua的key-value的查询过程:
模拟类
最简单的定义类的方法,即直接使用Lua内置的table描述类的属性和行为
Account = { balance = 100, withdraw = function(v) Account.balance = Account.balance - v end}
如果拿C++来类比的话,看起来有点像如下形式
class Account{ public int balance = 100; public void withdraw(int value){ balacne -= value; }}
不同的是在Lua中Account只是一个表,相当于一个对象,而C++中Account则是类,可以生成多个对象。
而且Lua的Account实现有很多值得吐槽的地方
- 在函数withdraw中直接访问全局变量Account
- 不能以Account为“模板”生成多个对象,一点都不符合类的概念
针对第一点,我们可以改成以下形式
function Account.withdraw(self, v) self.balance = self.balance - vendlocal obj = Accountobj.withdraw(obj,20)
这样看起来也很别扭,于是加入了语法糖:,变成下列形式
function Account:withdraw(v) self.balance = self.balance - vendlocal obj = Accountobj.withdraw(20)
接下来就要解决生成多个对象的问题了,其实也很简单,如果有一个名为Class的描述属性和操作的table,想让obj成为Class的对象(或者称让Class作为obj的原型),只需要:
setmetatable(obj, { __index = Class} )
即可
简单解释一下,在设定了元表之后,使用obj访问字段或者函数的时候,都会在Class这个表中寻找。(其实你可以发现,obj实际上是继承了Class)
为了更好的理解,给出一个比较完整的实例
Account = { balance = 100, withdraw = function(self, v) self.balance = self.balance - v end, new = function(self,obj) obj = obj or {} setmetatable(obj, self) self.__index = self return obj end}local o = Account:new()print(getmetatable(o))print(Account)for k,v in pairs(Account) do print(string.format("%-15s %-15s", tostring(k), tostring(v)))end
结果如下:
对照代码,我们可以画出一个大概的模型图
obj是new出来的对象,它的元表是Account这个表(因为是用Account:new()所以self是Account本身),而Account中定义的__index方法是它本身。
这样,在调用obj:withdraw(10)时,实际上走的是以下这个流程:
getmetatable(obj).__index.withdraw(10)getmetatable(obj) = AccountAccount.__index = Account最后就相当于Account.withdrwa(10)
这里,我曾有个疑问,为什么要
setmetatable(obj,self)self.__index = self
而不是直接
setmetatable(obj, {__index = self})
这里有两个原因
- 如果采用后者,每次new一个对象都要新建一个匿名的table,开销很大
- 使用前者还可以更方便的实现单一继承
单继承
如果想从Account派生一个新的的类SpecialAccount,我们可以这样写:
SpecialAccount = Account:new( {limit = 1000} )
如果只这样写,那么和new一个Account的对象没有什么区别,如果你写下列代码你会发现
for k,v in pairs(SpecialAccount) do print(string.format("%-15s %-15s", tostring(k), tostring(v)))end--输出结果是 limit 1000--只有属性limit
但是,如果你以SpecialAcoount为新的类new对象时,情况就变了
local sobj = SpecialAccount:new({})
SpecialAccount从Account那里继承了new,但是这次执行时,self是SpecialAccount
那么,sobj的元表是SpecialAccount,SpecialAccount的__index元方法仍然是SpecialAccount。
当执行sobj:withdraw(20)时,实际发生了下列过程:
- sobj中无withdraw字段,于是,getmetatable(sobj).__index.withdraw,也就是SpecialAccount中的withdraw
- 然而,SpecialAccount中也没有withdraw字段(只有limit字段),于是getmetatable(Special).__index.withdraw, 也就是Account中的withdrwa字段
这样,就实现了单一继承。SpecialAccount之所以特殊,是因为它可以重写从基类的继承的方法,仅需
function SpecialAccount:withdraw(value) -- body --do something differentend
最重要的是理解Lua的元表和元方法,理解Lua查找key的过程。
- lua 面向对象编程
- lua 面向对象编程
- Lua面向对象编程
- Lua面向对象编程
- Lua中的面向对象编程
- lua中的面向对象编程
- Lua中的面向对象编程
- Lua中的面向对象编程
- lua 的面向对象化编程
- COCOS2D-X Lua面向对象编程
- COCOS2D-X Lua 面向对象编程
- 基于closure的lua面向对象编程
- COCOS2D-X Lua 面向对象编程
- COCOS2D-X Lua面向对象编程
- Lua学习之6:面向对象编程
- lua语言实现面向对象编程
- Lua 基础之面向对象编程
- 【ulua入门】lua实现面向对象编程
- 二分查找相关题目
- php 数组怎么传递到html 怎么依靠json对象的形式操作
- centos挂载新硬盘并且设置开机启动
- c++运算符重载
- leetcode 438. Find All Anagrams in a String& 滑动窗口
- Lua面向对象编程
- 【Mongoose】populate基本使用
- EventBus的简单理解
- html表格实战<<简单的网页布局>>
- Python脚本练习
- .tar.bz2文件解压命令
- File.mkdirs和File.mkdir的区别
- 【解题报告】公司聚会
- 支付宝接口中notify_url 与 return_url 的区别