lua面向对象编程中冒号与点号的区别

时间:2022-09-18 17:25:59

看到一篇博客,详细解释了lua中冒号与点号的用法。文章详细讨论了几种情况,这里对原文作出补充

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

12345678910111213141516171819 Class
= {}
Class.__index
= Class
 function
Class:new(x,y)
    local temp = {}    setmetatable(temp, Class)    temp.x= x    temp.y= y    return tempend function
Class:test()
    print(self.x,self.y)end  object = Class.new(10,20) object:test()

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

输出:

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

我们的y值怎么没了?

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

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

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

12345678910111213141516171819 Class
= {}
Class.__index
= Class
 function
Class:new(x,y)
    local temp = {}    setmetatable(temp, Class)    temp.x= x    temp.y= y    return tempend function
Class:test()
    print(self.x,self.y)end  object = Class.new(self,10,20) object:test()

然后我们在看一下输出

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

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

然后代码改成

12345678910111213141516171819 Class
= {}
Class.__index
= Class
 function
Class:new(x,y)
    local temp = {}    setmetatable(temp, Class)    temp.x= x    temp.y= y    return tempend function
Class:test()
    print(self.x,self.y)end  object = Class:new(10,20) object:test()

输出正常:

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

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

12345678910111213141516171819 Class
= {}
Class.__index
= Class
 function
Class.new(x,y)
    local temp = {}    setmetatable(temp, Class)    temp.x= x    temp.y= y    return tempend function
Class:test()
    print(self.x,self.y)end  object = Class.new(10,20) object:test()

出乎意料的是:

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

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

然后,我接着尝试又发现

12345678910111213141516171819 Class
= {}
Class.__index
= Class
 function
Class.new(x,y)
    local temp = {}    setmetatable(temp, Class)    temp.x= x    temp.y= y    return tempend function
Class:test()
    print(self.x,self.y)end  object = Class:new(10,20) object:test()

输出结果:

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

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

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

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

12345678910111213141516171819 Class
= {}
Class.__index
= Class
 function
Class:new(x,y)
    local temp = {}    setmetatable(temp, Class)    temp.x= x    temp.y= y    return tempend function
Class.test()
    print(self.x,self.y)end  object = Class:new(10,20) 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这个参数,竟然,方法用的是点号,那我们试一下把对象传进去看下能不能正常运行

12345678910111213141516171819 Class
= {}
Class.__index
= Class
 function
Class:new(x,y)
    local temp = {}    setmetatable(temp, Class)    temp.x= x    temp.y= y    return tempend function
Class.test()
    print(self.x,self.y)end  object = Class:new(10,20) 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

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

12345678910111213141516171819 Class
= {}
Class.__index
= Class
 function
Class:new(x,y)
    local temp = {}    setmetatable(temp, Class)    temp.x= x    temp.y= y    return tempend function
Class.test()
    print(self.x,self.y)end  object = Class:new(10,20) object.test()

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

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

这次输出就正常了

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

以上是原文的解释,这里还有一种办法正确输出结果,代码如下:

12345678910111213141516171819 Class
= {}
Class.__index
= Class
 function
Class:new(x,y)
    local temp = {}    setmetatable(temp, Class)    temp.x= x    temp.y= y    return tempend function
Class.test(self)
    print(self.x,self.y)end  object = Class:new(10,20) object:test()
在Class.test中传入参数self,调用时利用冒号可以隐式的传入self参数,这样也能输出正确结果!

总结:冒号的作用是隐式的传递参数self,只要调用的时候与函数声明参数都一致,则不会出现问题。