Різниця між . і: в Луа


174

Мене плутає різниця між викликами функцій через .та через:

> 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

Що :робиш?


Відповіді:


237

Товста кишка призначена для реалізації методів, що передаються selfяк перший параметр. Так x:bar(3,4)має бути те саме, що x.bar(x,3,4).


55
ах ... так це об'єктно-орієнтований синтаксичний цукор.
Jason S

7
Саме так. У всьому довідковому посібнику єдиним розмиттям, яке вони надають на це, є "Синтаксис двокрапки використовується для визначення методів, тобто функцій, які мають неявний додатковий параметр". " (Посібник 5.0, внизу сторінки pdf, сторінка 19)
BMitch

2
ooh ах ... я збирався запитати, де офіційні документи з цього приводу, але ви побили мене. прекрасно зроблено. :-)
Джейсон S

1
@keyle Це залежить від того, як selfоб'єкт піде як перший параметр, так і значення його властивостей.
Hydroper

8
Синтаксис @keyle Colon був би трохи швидшим, якщо об’єкт, якого ви телефонуєте, не є локальним, оскільки віртуальна машина отримує його лише один раз. В основному крапковий синтаксис як object.method(object,args)витягується objectдвічі, тоді як object:method(arg)витягується objectлише один раз. Якщо objectце глобальне, оновлене або табличне поле, то :це швидше, ніж .. .ніколи не швидше, ніж :.
negamartin

28

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

Про використання :є майже такою ж , як .- особливий вид виклику буде використовуватися всередині , щоб переконатися , що objectі будь-які можливі побічні ефекти розрахунків / доступу обчислюються тільки один раз. Дзвінки object:method(arg1, arg2)інакше такі ж, як object.method(object, arg1, arg2).


21

Якщо бути абсолютно точним, 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).


Ви дійсно не повинні турбуватися про такі речі. Якщо у вас є, є що - то просто жахливо неправильно з вашої архітектурою.
val каже

2
Я б сказав, що це навпаки; хороший код не повинен робити жодних припущень щодо деталей реалізації непов'язаного коду. Функціональні дзвінки можуть запам'ятовуватися, а не можуть запам'ятовуватись, це не означає, що є гарною практикою дзвонити їм частіше, ніж потрібно.
DarkWiiPlayer
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.