Разница между ними. и: в Луа


Я запутался в разнице между вызовами функций через . и через :

> 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

что такое : делаешь ?

3 128

3 ответа:

двоеточие предназначено для реализации методов, которые проходят self в качестве первого параметра. Так что x:bar(3,4)должно быть то же самое, что и x.bar(x,3,4).

по определению ровно то же самое, что указать self вручную - он даже будет производить тот же байт-код при компиляции. То есть function object:method(arg1, arg2) такой же, как function object.method(self, arg1, arg2).

использовать : и почти то же самое, что . - специальный вид вызова будет использоваться внутри, чтобы убедиться object и любые возможные побочные эффекты вычислений / доступа рассчитываются только один раз. Звоню object:method(arg1, arg2) в противном случае то же самое, что object.method(object, arg1, arg2).

если быть совсем точным,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).