Différence entre . et: à Lua

174

Je ne comprends pas 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

Que :fait-on?

Jason S
la source

Réponses:

237

Les deux points servent à implémenter des méthodes qui passent selfcomme premier paramètre. Donc x:bar(3,4)devrait être le même que x.bar(x,3,4).

BMitch
la source
55
ah ... donc c'est du sucre syntaxique orienté objet.
Jason S
7
Exactement. Dans tout le manuel de référence, le seul texte de présentation qu'ils donnent à ce sujet est "La syntaxe deux-points est utilisée pour définir des méthodes, c'est-à-dire des fonctions qui ont un paramètre supplémentaire implicite self." (5.0 manuel, bas de la page pdf 19)
BMitch
2
ooh ahh ... J'allais demander où étaient les documents officiels à ce sujet, mais vous m'avez battu. Bien fait. :-)
Jason S
1
@keyle Cela dépend de l' selfobjet ira comme premier paramètre et sa valeur de propriétés.
Hydroper
8
La syntaxe @keyle Colon serait un peu plus rapide si l'objet que vous appelez n'est pas un local, puisque la machine virtuelle ne le récupère qu'une seule fois. Fondamentalement, la syntaxe de points comme object.method(object,args)récupère objectdeux fois, tandis que object:method(arg)récupère objectune seule fois. Si objectest un champ global, upvalue ou table, alors :est plus rapide que .. .n'est jamais plus rapide que :.
negamartin
28

Pour la définition, c'est exactement la même chose que de spécifier soi manuellement - cela produira même le même bytecode lors de la compilation. Ie function object:method(arg1, arg2)est le même que function object.method(object, arg1, arg2).

L'utilisation :est presque la même que .- un type spécial d'appel sera utilisé en interne pour s'assurer que objecttous les effets secondaires possibles des calculs / accès ne sont calculés qu'une seule fois. L'appel object:method(arg1, arg2)est par ailleurs le même que object.method(object, arg1, arg2).

Oleg V. Volkov
la source
21

Pour être tout à fait précis, obj:method(1, 2, 3)équivaut à

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

Pourquoi la variable locale? Parce que, comme beaucoup l'ont souligné, les obj:method()index ne sont disponibles qu'une seule _ENVfois obj. Ceci est normalement juste important lors de l'examen de 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 __indexmétaméthode a fait 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 faire cela 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).

DarkWiiPlayer
la source
Vous ne devriez vraiment pas vous soucier de telles choses. Si vous devez le faire, il y a quelque chose qui ne va vraiment pas dans votre architecture.
val dit Réintégrer Monica le
2
Je dirais que c'est l'inverse; un bon code ne devrait pas faire d'hypothèses sur les détails d'implémentation d'un code non lié. Les appels de fonction peuvent ou non être mémorisés, cela ne signifie pas qu'il est recommandé de les appeler plus souvent que nécessaire.
DarkWiiPlayer