Je suis confus quant à la différence entre les appels de fonction via .
et via :
> 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
Quel est le :
Faire ?
Le deux-points sert à implémenter des méthodes qui passent self
comme premier paramètre. Donc x:bar(3,4)
devrait être identique à x.bar(x,3,4)
.
Pour la définition, c'est exactement la même chose que de spécifier soi-même manuellement - cela produira même le même bytecode lors de la compilation. C'est à dire. function object:method(arg1, arg2)
est identique à function object.method(self, arg1, arg2)
.
Lors de l'utilisation, :
Est presque identique à .
- un type spécial d'appel sera utilisé en interne pour s'assurer que object
et tout côté possible- les effets des calculs/accès ne sont calculés qu'une seule fois. L'appel de object:method(arg1, arg2)
est par ailleurs identique à object.method(object, arg1, arg2)
.
Pour être complètement précis, obj:method(1, 2, 3)
est identique à
do
local _obj = obj
_obj.method(_obj, 1, 2, 3)
end
Pourquoi la variable locale? Parce que, comme beaucoup l'ont souligné, obj:method()
indexe _ENV
Une seule fois pour obtenir obj
. Cela est normalement important pour la vitesse, mais considérez cette situation:
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
Imaginez maintenant que la métaméthode __index
Fasse plus que simplement imprimer quelque chose. Imaginez qu'il augmente un compteur, enregistre quelque chose dans un fichier ou supprime un utilisateur aléatoire de votre base de données. Il y a une grande différence entre le faire deux fois ou une seule fois. Dans ce cas, il y a une nette différence entre obj.method(obj, etc)
et obj:method(etc)
.