Unterschied zwischen . und: in Lua

174

Ich bin verwirrt über den Unterschied zwischen Funktionsaufrufen über .und über:

> 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

Was ist das :?

Jason S.
quelle
1
Siehe auch
finnw

Antworten:

237

Der Doppelpunkt dient zum Implementieren von Methoden, die selfals erster Parameter übergeben werden. Also x:bar(3,4)sollte das gleiche sein wie x.bar(x,3,4).

BMitch
quelle
55
ah ... also ist es objektorientierter syntaktischer Zucker.
Jason S
7
Genau. Im gesamten Referenzhandbuch ist der einzige Klappentext, den sie dazu geben, "Die Doppelpunktsyntax wird zum Definieren von Methoden verwendet, dh Funktionen, die einen impliziten zusätzlichen Parameter self haben." (5.0 Handbuch, unten im PDF Seite 19)
BMitch
2
ooh ahh ... Ich wollte fragen, wo die offiziellen Dokumente dazu sind, aber du hast mich geschlagen. schön gemacht. :-)
Jason S
1
@keyle Es hängt davon ab, ob das selfObjekt als erster Parameter und sein Eigenschaftenwert verwendet wird.
Hydroper
8
Die @ keyle Colon-Syntax wäre etwas schneller, wenn das von Ihnen aufgerufene Objekt kein lokales Objekt ist, da die virtuelle Maschine es nur einmal abruft. Grundsätzlich wird die Punktsyntax wie zweimal object.method(object,args)abgerufen object, während nur einmal object:method(arg)abgerufen wird object. Wenn objectes sich um ein globales Feld, ein Upvalue-Feld oder ein Tabellenfeld handelt, :ist es schneller als .. .ist nie schneller als :.
Negamartin
28

Für die Definition ist es genau das Gleiche wie die manuelle Angabe von self - es wird sogar der gleiche Bytecode beim Kompilieren erzeugt. Dh function object:method(arg1, arg2)ist das gleiche wie function object.method(object, arg1, arg2).

Bei Verwendung :ist fast das Gleiche wie .- eine spezielle Art von Anruf wird intern verwendet, um sicherzustellen, objectdass mögliche Nebenwirkungen von Berechnungen / Zugriff nur einmal berechnet werden. Das Anrufen object:method(arg1, arg2)ist ansonsten dasselbe wie object.method(object, arg1, arg2).

Oleg V. Volkov
quelle
21

Um ganz genau zu sein, obj:method(1, 2, 3)ist das gleiche wie

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

Warum die lokale Variable? Weil, wie viele darauf hingewiesen haben, obj:method()nur _ENVeinmal Indizes abgerufen werden müssen obj. Dies ist normalerweise nur wichtig, wenn Sie die Geschwindigkeit berücksichtigen. Beachten Sie jedoch die folgende 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

Stellen __indexSie sich nun vor, die Metamethode hat mehr als nur etwas gedruckt. Stellen Sie sich vor, es würde einen Zähler erhöhen, etwas in einer Datei protokollieren oder einen zufälligen Benutzer aus Ihrer Datenbank löschen. Es gibt einen großen Unterschied, ob man das zweimal oder nur einmal macht. In diesem Fall gibt es einen deutlichen Unterschied zwischen obj.method(obj, etc)und obj:method(etc).

DarkWiiPlayer
quelle
Sie sollten sich wirklich keine Sorgen um solche Dinge machen. Wenn Sie müssen, stimmt etwas schrecklich mit Ihrer Architektur nicht.
Val sagt Reinstate Monica
2
Ich würde sagen, es ist umgekehrt; Guter Code sollte keine Annahmen über Implementierungsdetails von nicht verwandtem Code treffen. Funktionsaufrufe können gespeichert oder nicht gespeichert werden. Dies bedeutet nicht, dass es empfehlenswert ist, sie häufiger als erforderlich aufzurufen.
DarkWiiPlayer