Differenza tra . e: in Lua


174

Sono confuso sulla differenza tra chiamate di funzione via .e 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

Che cosa sta :facendo?


Risposte:


237

I due punti sono per l'implementazione di metodi che passano selfcome primo parametro. Quindi x:bar(3,4)dovrebbe essere lo stesso di x.bar(x,3,4).


55
ah ... quindi è zucchero sintattico orientato agli oggetti.
Jason S,

7
Esattamente. In tutto il manuale di riferimento, l'unico blurb che danno su questo è "La sintassi dei due punti è usata per definire metodi, cioè funzioni che hanno un auto implicito parametro extra". (Manuale 5.0, in fondo alla pagina pdf 19)
BMitch

2
ooh ahh ... stavo per chiedere dove fossero i documenti ufficiali su questo, ma mi hai battuto. ben fatto. :-)
Jason S,

1
@keyle Dipende selfdall'oggetto che andrà come primo parametro e dal suo valore delle proprietà.
Idroper

8
La sintassi di @keyle Colon sarebbe un po 'più veloce se l'oggetto che stai chiamando non è un locale, poiché la macchina virtuale lo recupera solo una volta. Fondamentalmente dot la sintassi come object.method(object,args)recupera objectdue volte, mentre object:method(arg)recupera objectsolo una volta. Se objectè un campo globale, upvalue o table, allora :è più veloce di .. .non è mai più veloce di :.
negamartin,

28

Per definizione è esattamente lo stesso di specificare auto manualmente - produrrà anche lo stesso bytecode durante la compilazione. Cioè function object:method(arg1, arg2)è lo stesso di function object.method(object, arg1, arg2).

In uso :è quasi lo stesso di .: un tipo speciale di chiamata verrà utilizzato internamente per assicurarsi objectche tutti i possibili effetti collaterali di calcoli / accesso vengano calcolati una sola volta. La chiamata object:method(arg1, arg2)è altrimenti uguale a object.method(object, arg1, arg2).


21

Per essere completamente precisi, obj:method(1, 2, 3)è lo stesso di

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

Perché la variabile locale? Perché, come molti hanno sottolineato, obj:method()solo gli indici _ENVuna volta per ottenere obj. Questo di solito è importante solo se si considera la velocità, ma considerare questa situazione:

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

Ora immagina che il __indexmetametodo abbia fatto molto di più che stampare semplicemente qualcosa. Immagina di aver aumentato un contatore, registrato qualcosa in un file o eliminato un utente casuale dal tuo database. C'è una grande differenza tra farlo due volte o solo una volta. In questo caso, c'è una chiara differenza tra obj.method(obj, etc)e obj:method(etc).


Non dovresti davvero preoccuparti di queste cose. Se devi, c'è qualcosa di terribilmente sbagliato nella tua architettura.
dice Val Reinstate Monica il

2
Direi che è il contrario; il buon codice non dovrebbe fare ipotesi sui dettagli di implementazione del codice non correlato. Le chiamate di funzione possono o meno essere memorizzate, ciò non significa che sia buona norma chiamarle più spesso del necessario.
DarkWiiPlayer
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.