之间的区别。和:在Lua


174

我对通过.和通过函数调用之间的区别感到困惑:

> x = {foo = function(a,b) return a end, bar = function(a,b) return b end, }
> return x.foo(3,4)
3
> return x.bar(3,4)
4
> return x:foo(3,4)
table: 0x10a120
> return x:bar(3,4)
3

:做什么?


Answers:


237

冒号用于实现self作为第一个参数传递的方法。因此x:bar(3,4)应与相同x.bar(x,3,4)


55
啊...所以它是面向对象的语法糖。
詹森·S

7
究竟。在整个参考手册中,他们对此给出的唯一说明是“冒号语法用于定义方法,即具有隐式额外参数self的函数。” (5.0手册,pdf页面19的底部)
BMitch 2011年

2
哦,我要问的是官方文档在哪儿,但是你击败了我。做得很好。:-)
Jason S

1
@keyle取决于self对象将作为第一个参数及其属性值。
Hydroper

8
如果您要调用的对象不是本地对象,则@keyle Colon语法会更快一些,因为虚拟机只能检索一次。基本上,点语法如两次object.method(object,args)检索object,而一次仅object:method(arg)检索object一次。如果object是全局字段,高:值字段或表字段,则比快..永远不会比:
negamartin

28

对于定义,它与手动指定self 完全相同 -甚至在编译时会产生相同的字节码。即function object:method(arg1, arg2)function object.method(object, arg1, arg2)

关于使用:几乎一样的.-一种特殊的调用将在内部使用,以确保object和计算/访问的任何可能的副作用是只有一次计算。呼叫object:method(arg1, arg2)与相同object.method(object, arg1, arg2)


21

确切地说,obj:method(1, 2, 3)

do
  local _obj = obj
  _obj.method(_obj, 1, 2, 3)
end

为什么要使用局部变量?因为,正如许多人指出的那样,obj:method()只有索引_ENV一次才能获得obj。这通常在考虑速度时才很重要,但请考虑以下情况:

local tab do
  local obj_local = { method = function(self, n) print n end }
  tab = setmetatable({}, {__index = function(idx)
    print "Accessing "..idx
    if idx=="obj" then return obj_local end
  end})
end
tab.obj.method(tab.obj, 20)
--> Accessing obj
--> Accessing obj
--> 20
tab.obj:method(10)
--> Accessing obj
--> 10

现在,想象一下元__index方法所做的不仅仅是打印某些内容。想象一下,它增加了一个计数器,在文件中记录了一些内容,或者从数据库中删除了一个随机用户。两次或仅一次执行之间有很大的区别。在这种情况下,obj.method(obj, etc)和之间有明显的区别obj:method(etc)


您真的不应该担心这些东西。如果必须的话,您的体系结构可能存在严重错误。
瓦尔说,请恢复莫妮卡(Monica),

2
我会说相反。好的代码不应对无关代码的实现细节做任何假设。函数调用可能被记住,也可能未被记住,这并不意味着多次调用它们是一种好习惯。
DarkWiiPlayer19年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.