理解冒号和句点运算符

很多学习 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(),这个方法需要两个参数:parameter1parameter2。但是,该方法不知道与之关联的对象,这可能会引起限制。

第二个函数 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 识别 selfobject 是相同的,以及我们添加的 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

基本上,此错误消息告诉你 parameter2nil,但这可能会令人困惑,因为两个参数都已明确传入。发生此错误的原因是,如上所述,冒号方法以 self 作为隐式的第一个参数,因此对于函数而言,参数是

  1. self"Hello"
  2. parameter1"World"
  3. parameter2nil

相反,尝试像这样正确调用函数

object:colonMethod( "Hello", "World" )  -- COLON method called with COLON operator (correct)

现在,结果符合预期,并且从函数的角度来看,参数是

  1. selfobject
  2. parameter1"Hello"
  3. parameter2“世界”

总结

了解此信息后,你就能更好地理解什么时候使用冒号运算符,什么时候使用点运算符,从而确保你的代码是有逻辑的且没有 bug 的.