很多学习 Lua 的程序员第一次会纠结于用冒号 (:
) 把方法和对象分开和用句点/句号 (.
) 把它们分开这两个函数调用之间的区别。我们从看两个示例开始
local length = string.len( "Hello World" )
Runtime:addEventListener( "enterFrame", gameLoop )
在第一个示例中,string
是对象,len
是其方法之一(在本例中,它获取 string 的长度)。
第二个示例调用了 Runtime
对象的方法 addEventListener
,以及一些参数/自变量。
决定是使用冒号还是句点语法通常取决于你是否需要在函数中进行对象引用。对于独立的函数,这一点当然无关紧要,但是对于定义为对象的 方法的函数,这一点可能极其重要。
考虑这个通用模块
local object = {} function object.dotMethod( parameter1, parameter2 ) end function object:colonMethod( parameter1, parameter2 ) end
首先,我们设置一个对象 (object
) — 在本例中,就是一个空的 Lua 表。
接下来,对于第一个函数,我们定义了一个 object
的方法,称为 dotMethod()
,这个方法需要两个参数:parameter1
和 parameter2
。但是,该方法不知道与之关联的对象,这可能会引起限制。
第二个函数 colonMethod()
有一个主要区别 — 它使用冒号 (:
) 运算符,因此,该方法有一个额外的“不可见”参数,称为 self
。你可能猜到了,这个 self
参数是对对象本身(在本例中为 object
)的引用。可以通过扩展上面的代码来测试这一点
local object = {} function object.dotMethod( parameter1, parameter2 ) print( self.someNumber ) end function object:colonMethod( parameter1, parameter2 ) print( self.someNumber ) end object.someNumber = 10 object.dotMethod( "Hello", "World" ) -- Dot method called with dot operator object:colonMethod( "Hello", "World" ) -- Colon method called with colon operator
运行此代码,你会看到控制台中的结果是
nil 10
为什么会有差别?如上所述,隐式的 self
参数不包含在句点运算符方法中,因此 Lua 输出 nil
。相反,在冒号运算符方法中可以访问 self
参数,因此 Lua 识别 self
和 object
是相同的,以及我们添加的 someNumber
属性,因此输出是 10
。
请注意,在错误的时间使用句点或冒号可能会导致代码出错。Lua 编译器会准确告诉你问题是什么,但解读错误消息可能很棘手。考虑以下示例
local object = {} function object:colonMethod( parameter1, parameter2 ) print( self ) print( parameter1 .. " " .. parameter2 ) end object.colonMethod( "Hello", "World" ) -- COLON method called with DOT operator (incorrect)
运行此代码将生成此错误
lua: mymodule.lua:5: attempt to concatenate local 'parameter2' (a nil value) stack traceback: mymodule.lua:5: in function 'colonMethod' mymodule.lua:8: in main chunk
基本上,此错误消息告诉你 parameter2
为 nil
,但这可能会令人困惑,因为两个参数都已明确传入。发生此错误的原因是,如上所述,冒号方法以 self
作为隐式的第一个参数,因此对于函数而言,参数是
self
→ "Hello"
parameter1
→ "World"
parameter2
→ nil
相反,尝试像这样正确调用函数
object:colonMethod( "Hello", "World" ) -- COLON method called with COLON operator (correct)
现在,结果符合预期,并且从函数的角度来看,参数是
self
→ object
parameter1
→ "Hello"
parameter2
→ “世界”
了解此信息后,你就能更好地理解什么时候使用冒号运算符,什么时候使用点运算符,从而确保你的代码是有逻辑的且