lua面向对象编程之点号与冒号的差异详细比较

简介:

首先,先来一段在lua创建一个类与对象的代码

 
  1. Class = {}  
  2. Class.__index = Class   
  3. function Class:new(x,y)      
  4. local temp = {}      
  5. setmetatable(temp, Class)      
  6. temp.x = x      
  7. temp.y = y      
  8. return tempend   
  9. function Class:test()      
  10. print(self.x,self.y)end    
  11. object = Class.new(10,20)   
  12. object:test() 

猜一下会输出什么结果呢?

输出:

>lua -e "io.stdout:setvbuf 'no'" "object.lua" 
20 nil
>Exit code: 0

我们的y值怎么没了?

这个原因很简单,因为我们创建一个对象的时候使用了一个 . 号

在lua程序设计第二版中,有提到当一项操作所作用的”接受者”,需要一个额外的参数来表示该接受者,这个参数通常称为self或this

然后我们在这段代码加上 self

 
  1. Class = {}  
  2. Class.__index = Class   
  3. function Class:new(x,y)      
  4. local temp = {}      
  5. setmetatable(temp, Class)      
  6. temp.x = x      
  7. temp.y = y      
  8. return tempend   
  9. function Class:test()      
  10. print(self.x,self.y)end    
  11. object = Class.new(self,10,20)   
  12. object:test() 

然后我们在看一下输出

>lua -e "io.stdout:setvbuf 'no'" "object.lua" 
10 20
>Exit code: 0

这下就正常了!!嗯,每次创建一个对象的时候都有写一个self,会不会感觉很麻烦呢?lua提供了用冒号的方式在一个方法定义中添加一个额外的参数,以及在一个方法调用中添加一个额外的实参

然后代码改成

 
  1. Class = {}  
  2. Class.__index = Class   
  3. function Class:new(x,y)      
  4. local temp = {}      
  5. setmetatable(temp, Class)      
  6. temp.x = x      
  7. temp.y = y      
  8. return tempend   
  9. function Class:test()      
  10. print(self.x,self.y)end    
  11. object = Class:new(10,20)   
  12. object:test() 

输出正常:

>lua -e "io.stdout:setvbuf 'no'" "object.lua" 
10 20
>Exit code: 0

如果,就这么完的话,本来是一件很欢乐的事情,但是,我尝试了一下以下代码

 
  1. Class = {}  
  2. Class.__index = Class   
  3. function Class.new(x,y)      
  4. local temp = {}      
  5. setmetatable(temp, Class)      
  6. temp.x = x      
  7. temp.y = y      
  8. return tempend   
  9. function Class:test()      
  10. print(self.x,self.y)end    
  11. object = Class.new(10,20)   
  12. object:test() 

出乎意料的是:

>lua -e "io.stdout:setvbuf 'no'" "object.lua" 
10 20
>Exit code: 0

代码正常运行….这个让人很费解,本来,点号对方法的操作是需要一个额外的接受者,第一段代码已经说明了这个问题,但是,现在程序有正常运行,令我真是有点费解…

然后,我接着尝试又发现

 
  1. Class = {}  
  2. Class.__index = Class   
  3. function Class.new(x,y)      
  4. local temp = {}      
  5. setmetatable(temp, Class)      
  6. temp.x = x      
  7. temp.y = y      
  8. return tempend   
  9. function Class:test()      
  10. print(self.x,self.y)end    
  11. object = Class:new(10,20)   
  12. object:test() 

输出结果:

>lua -e "io.stdout:setvbuf 'no'" "object.lua" 
table: 003CACA0 10
>Exit code: 0

这个只不过跟第一段代码点号和冒号的位置调换了一下,就出现了这样的结果…

如果,你仔细想想,这里和第一段代码的区别,可以发现,其实,这里就可以证明了冒号其实就是默认传了一个实参到方法中

为了证明冒号的作用,我改动了一下代码

 
  1. Class = {}  
  2. Class.__index = Class   
  3. function Class:new(x,y)      
  4. local temp = {}      
  5. setmetatable(temp, Class)      
  6. temp.x = x      
  7. temp.y = y      
  8. return tempend   
  9. function Class.test()      
  10. print(self.x,self.y)end    
  11. object = Class:new(10,20)   
  12. object:test() 

输出的结果是:

>lua -e "io.stdout:setvbuf 'no'" "object.lua" 
lua: object.lua:15: attempt to index global 'self' (a nil value)
stack traceback:
object.lua:15: in function 'test'
object.lua:21: in main chunk
[C]: ?
>Exit code: 1

从这里的错误可以看出,没有self这个参数,竟然,方法用的是点号,那我们试一下把对象传进去看下能不能正常运行

 
  1. Class = {}  
  2. Class.__index = Class   
  3. function Class:new(x,y)      
  4. local temp = {}      
  5. setmetatable(temp, Class)      
  6. temp.x = x      
  7. temp.y = y      
  8. return tempend   
  9. function Class.test()      
  10. print(self.x,self.y)end    
  11. object = Class:new(10,20)   
  12. object:test(object) 

遗憾的是这样的改动是错误的,错误的结果也是一样的

>lua -e "io.stdout:setvbuf 'no'" "object.lua" 
lua: object.lua:15: attempt to index global 'self' (a nil value)
stack traceback:
object.lua:15: in function 'test'
object.lua:21: in main chunk
[C]: ?
>Exit code: 1

那我们这次尝试下想刚才那样,把方法的点号搞成一致看下效果怎样

 
  1. Class = {}  
  2. Class.__index = Class   
  3. function Class:new(x,y)      
  4. local temp = {}      
  5. setmetatable(temp, Class)      
  6. temp.x = x      
  7. temp.y = y      
  8. return tempend   
  9. function Class.test()      
  10. print(self.x,self.y)end    
  11. object = Class:new(10,20)   
  12. object.test() 

遗憾的是跟之前不一样,还是不能运行

 
  1. Class = {}  
  2. Class.__index = Class   
  3. function Class:new(x,y)      
  4. local temp = {}      
  5. setmetatable(temp, Class)      
  6. temp.x = x      
  7. temp.y = y      
  8. return tempend   
  9. function Class.test()      
  10. print(self.x,self.y)end    
  11. object = Class:new(10,20)   
  12. object.test() 
回想一下,冒号的作用可以传递一个实参,对于方法的操作我们需要一个接受者,那么进行以下的改动
 
  1. Class = {}  
  2. Class.__index = Class   
  3. function Class:new(x,y)      
  4. local temp = {}      
  5. setmetatable(temp, Class)      
  6. temp.x = x      
  7. temp.y = y      
  8. return tempend   
  9. function Class:test()      
  10. print(self.x,self.y)end    
  11. object = Class:new(10,20)   
  12. object.test(object) 

这次输出就正常了

>lua -e "io.stdout:setvbuf 'no'" "object.lua" 
10 20
>Exit code: 0

这段代码告诉了我们,想要操作一个方法就一定需要一个额外参数来表示该值,对于点号,我们必须显示传递一个实参,才能使程序正常运行,而为了方便,我们可以直接使用冒号来简化操作.

结论:

罗嗦了半天其实,可以用一下一句话来避免这个问题:

用lua进行面向对象的编程,声明方法和调用方法统一用冒号,对于属性的调用全部用点号 


 

搞这么多其实,只是加深理解罢了…欢迎交流和批评..


本文转自 liam2199 博客,原文链接:http://blog.51cto.com/youxilua/773047   如需转载请自行联系原作者


相关文章
|
C++ 索引
LUA面向对象编程技巧
详文请见 http://ffown.sinaapp.com/?p=11 1. LUA中的对象 我们知道,对象由属性和方法组成。LUA中最基本的结构是table,So 必须用table描述对象的属性。
1052 0
|
存储 NoSQL Redis
Redis的Lua脚本有什么作用?
Redis Lua脚本用于减少网络开销、实现原子操作及扩展指令集。它能合并操作降低网络延迟,保证原子性,替代不支持回滚的事务。通过脚本,代码复用率提高,且可自定义指令,如实现分布式锁,增强Redis功能和灵活性。
673 1
|
缓存 NoSQL 搜索推荐
【📕分布式锁通关指南 03】通过Lua脚本保证redis操作的原子性
本文介绍了如何通过Lua脚本在Redis中实现分布式锁的原子性操作,避免并发问题。首先讲解了Lua脚本的基本概念及其在Redis中的使用方法,包括通过`eval`指令执行Lua脚本和通过`script load`指令缓存脚本。接着详细展示了如何用Lua脚本实现加锁、解锁及可重入锁的功能,确保同一线程可以多次获取锁而不发生死锁。最后,通过代码示例演示了如何在实际业务中调用这些Lua脚本,确保锁操作的原子性和安全性。
786 6
【📕分布式锁通关指南 03】通过Lua脚本保证redis操作的原子性
|
消息中间件 NoSQL Java
Redis系列学习文章分享---第六篇(Redis实战篇--Redis分布式锁+实现思路+误删问题+原子性+lua脚本+Redisson功能介绍+可重入锁+WatchDog机制+multiLock)
Redis系列学习文章分享---第六篇(Redis实战篇--Redis分布式锁+实现思路+误删问题+原子性+lua脚本+Redisson功能介绍+可重入锁+WatchDog机制+multiLock)
788 0
|
NoSQL Redis 数据库
Redis 功能扩展 Lua 脚本 对Redis扩展 eval redis.call redis.pcall
通过本文的介绍,我们详细讲解了 Lua 脚本在 Redis 中的作用、`eval` 命令的使用方法以及 `redis.call` 和 `redis.pcall` 的区别和用法。通过合理使用 Lua 脚本,可以实现复杂的业务逻辑,确保操作的原子性,并减少网络开销,从而提高系统的性能和可靠性。
1037 13
|
监控 安全
公司用什么软件监控电脑:Lua 脚本在监控软件扩展功能的应用
在企业环境中,电脑监控软件对保障信息安全、提升效率至关重要。Lua 脚本在此类软件中用于扩展功能,如收集系统信息、监控软件使用时长及文件操作,向指定服务器发送数据,支持企业管理和运营。
289 6
|
缓存 分布式计算 NoSQL
大数据-43 Redis 功能扩展 Lua 脚本 对Redis扩展 eval redis.call redis.pcall
大数据-43 Redis 功能扩展 Lua 脚本 对Redis扩展 eval redis.call redis.pcall
253 2
|
存储 JSON Ubuntu
如何使用 Lua 脚本进行更复杂的网络请求,比如 POST 请求?
如何使用 Lua 脚本进行更复杂的网络请求,比如 POST 请求?
|
JSON 监控 数据格式
使用Lua代码扩展上网行为管理软件的脚本功能
本文介绍了如何使用Lua脚本增强上网行为管理,包括过滤URL、记录用户访问日志、控制带宽和自动提交监控数据到网站。Lua是一种轻量级语言,适合编写扩展脚本。文中提供多个示例代码,如URL过滤器、用户活动日志记录器和带宽控制器,帮助用户根据需求定制网络管理功能。通过这些示例,用户可以快速掌握Lua在上网行为管理中的应用。
417 4