介绍
在lua中,表拥有一个标识:self。self类似于this指针,大多数面向对象的语言(比如C++、C#)都隐藏了这个机制,在编码时不需要显式地声明这个参数,就可以在方法内使用this。在lua中,提供了冒号操作符来隐藏self参数,比如:
local t = {a = 1, b = 2}
function t:Add()
return (self.a + self.b)
end
print(t.Add())
冒号和点号实现同样的功能
冒号有两个作用:1.对于方法定义来说,提供了一个额外的隐藏形参(即self)。2.对于函数调用来说,会增加一个额外的实参(调用者本身)。
冒号其实是一种语法机制,点号与冒号可以完成同样的事情,例如:
--用冒号和点号实现同样的函数调用
--冒号实现
local tA = {a = 1, b = 2}
function tA:Add()
return (self.a + self.b)
end
print(tA.Add())
--点号实现
local tB = {a = 1, b = 2}
function tB.Add(self)
return (self.a + self.b)
end
print(tB.Add(tB))
冒号和点号的区别
拿上面那个等价的例子来说:
对于冒号实现,print(tA.Add())生成的指令如下:

可以看到有一个self指令,lua中的指令分为四类:IABC、iABx、iAsBx、iAx。self指令属于iABC类型,他会将表对象和函数拷贝到寄存器的连续两个位置中,寄存器索引由操作数A指定,表对象在寄存器中的位置由操作数B指定,函数的位置由操作数C指定。
在指令序列中,首先获取全局环境中的print函数,然后self指令做了两件事:获取表中的Add函数以及将表压入栈顶(冒号语法会将表自身作为实参传入给Add函数)。然后是两条函数调用指令CALL,分别调用Add函数与print函数。总共需要4条指令。
而对于点号实现,print(tB.Add(tB))生成的指令如下:

在指令序列中,首先和冒号一样获取全局环境中的print函数,然后获取表中的Add函数,然后通过MOVE指令将表压入栈顶。接着是同样的两个函数调用指令Call。总共需要5条指令。
总结
1.冒号和点号是lua中不同的语法机制,通过self可以实现一样的功能。
2.冒号语法比点号语法节省一条指令,可提供一点点性能优化。
本文介绍了Lua中的self概念,以及冒号和点号在方法定义和调用中的作用。冒号用于隐式传递self参数,而点号则需要显式传入。虽然两者功能相同,但冒号语法在指令执行上较点号略有优势,能节省一条指令,带来轻微的性能提升。
7152

被折叠的 条评论
为什么被折叠?



