最近在学习lua,碰到点号和冒号的使用,乍看的确很绕人。所以写此笔记以帮助自己加深印象。先看代码:



--
-- Author: right
-- Date: 2014-04-26 13:30:42
--
Class = {}
Class.__index = Class

function Class:new(x , y)
    local temp = {}
    setmetatable(temp , Class)
    temp.x = x
    temp.y = y
    return temp
end

function Class:test()
    print(self.x , self.y)
end

temp = Class:new(10 , 20)
temp:test()



该段代码摘自一位网友对该知识点的具体分析。

现在首先要解释的就是点号和冒号的使用区别:

使用冒号进行申明那么在访问时可以通过如下两种进行

方法一:



--
-- Author: right
-- Date: 2014-04-26 13:30:42
--
Class = {}
Class.__index = Class

function Class:new(x , y)
    local temp = {}
    setmetatable(temp , Class)
    temp.x = x
    temp.y = y
    return temp
end

function Class:test()
    print(self.x , self.y)
end

temp = Class.new(self,10 , 20)
temp:test()



方法二:



--
-- Author: right
-- Date: 2014-04-26 13:30:42
--
Class = {}
Class.__index = Class

function Class:new(x , y)
    local temp = {}
    setmetatable(temp , Class)
    temp.x = x
    temp.y = y
    return temp
end

function Class:test()
    print(self.x , self.y)
end

temp = Class:new(10 , 20)
temp:test()



仔细对比方法一和方法二,你会发现如果在使用冒号进行方法申明后,调用时想通过点号访问必须要加一个self额外参数进行参数补充,这个算是lua的基本语法规则。

但是我现在又想用点号访问又不想传self怎么做?代码如下



--
-- Author: right
-- Date: 2014-04-26 13:30:42
--
Class = {}
Class.__index = Class

function Class.new(x , y)
    local temp = {}
    setmetatable(temp , Class)
    temp.x = x
    temp.y = y
    return temp
end

function Class:test()
    print(self.x , self.y)
end

temp = Class.new(10 , 20)
temp:test()



此时我new方法使用点号进行申明,同样也使用点号进行访问。怎么样?是不是感觉点号很靠谱,好吧,你是不是已经准备把test方法也改成这样?然后对自己的打印结果已经信心满满了?好吧,让我们试下代码如下



--
-- Author: right
-- Date: 2014-04-26 13:30:42
--
Class = {}
Class.__index = Class

function Class:new(x , y)
    local temp = {}
    setmetatable(temp , Class)
    temp.x = x
    temp.y = y
    return temp
end

function Class.test()
    print(self.x , self.y)
end

temp = Class:new(10 , 20)
temp.test()

错误:attempt to index global 'self' (a nil value)



是不是发蒙了?为什么上面的new方法改成点号申明,下面使用点号可以直接访问,为什么现在我test改成这样就不行了?这个归根结底得追究他本身的代码块执行区域了。那是因为new方法中并未涉及到self值的调用,一旦存在self调用肯定也就报错了。所有想通过点号调用test方法的对象都给我添加一个self参数过来,不然我这边的self都是空的

那么就变成了如下代码



--
-- Author: right
-- Date: 2014-04-26 13:30:42
--
Class = {}
Class.__index = Class

function Class:new(x , y)
    local temp = {}
    setmetatable(temp , Class)
    temp.x = x
    temp.y = y
    return temp
end

function Class.test(self)
    print(self.x , self.y)
end

temp = Class:new(10 , 20)
temp.test(temp)

结果:
10    20
[Finished in 0.1s]



如果new方法中也和test方法一样存在self调用看他是不是还有直接通过点号申明就可以通过点号直接调用的权利?代码如下:



--
-- Author: right
-- Date: 2014-04-26 13:30:42
--
Class = {}
Class.__index = Class

function Class.new(x , y)
    print(self.x , self.y)
    local temp = {}
    setmetatable(temp , Class)
    temp.x = x
    temp.y = y
    return temp
end

function Class.test(self)
    print(self.x , self.y)
end

temp = Class.new(10 , 20)
temp.test(temp)

结果:
lua:9: attempt to index global 'self' (a nil value)



这个时候你不传self给我看你怎么嘚瑟。new方法和test方法本质的区别就在这了,一个有self访问一个没有。同时我们需要深入的理解self到底是指什么?他的词法域在什么地方?

具体可以先行翻阅下资料,此处不详细解释。那么要如何修改正确呢?代码如下



--
-- Author: right
-- Date: 2014-04-26 13:30:42
--
Class = {}
Class.__index = Class

function Class.new(self , x , y)
    print(self.x , self.y)
    local temp = {}
    setmetatable(temp , Class)
    temp.x = x
    temp.y = y
    return temp
end

function Class.test(self)
    print(self.x , self.y)
end

temp = Class.new(Class , 10 , 20)
temp.test(temp)

结果:
nil    nil
10    20
[Finished in 0.1s]



虽然Class的new打印出来的值是nil但是最起码说明了点号必须要传额参数的基础知识。第一段代码进化到最后一段代码是不是由冒号全部改成了逗号,是不是感觉要用逗号访问很繁琐呢?所以我稍微总结了下:点号本身不会将访问某个方法的对象传递给具体的方法类似于temp.test()这个地方是需要把temp放到test方法里面去的。但是冒号会帮我们做掉temp:test()可以等同于temp.test(temp),前提是你test申明时就是使用冒号,这样这个方法才有资格默认接受一个self参数,用点号申明是没有这个功能的,你需要自己手动在申明的时候添加一个形参才可以。冒号用于方法的申明和访问,这样可以省去所有的额外参数的传递,不用你去烦了。逗号可以用于属性的访问譬如上面的x,y这些。