Perbedaan antara . dan: di Lua

174

Saya bingung tentang perbedaan antara panggilan fungsi via .dan 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

Apa yang sedang :dilakukan?

Jason S
sumber

Jawaban:

237

Usus besar untuk menerapkan metode yang lulus selfsebagai parameter pertama. Jadi x:bar(3,4)harus sama dengan x.bar(x,3,4).

BMitch
sumber
55
ah ... jadi itu gula sintaksis berorientasi objek.
Jason S
7
Persis. Dalam keseluruhan manual referensi, satu-satunya uraian singkat yang mereka berikan pada ini adalah "Sintaks usus besar digunakan untuk mendefinisikan metode, yaitu, fungsi-fungsi yang memiliki parameter diri tambahan implisit." (5.0 manual, bawah pdf halaman 19)
BMitch
2
ooh ahh ... saya akan bertanya di mana dokumen resmi tentang ini, tetapi Anda mengalahkan saya untuk itu. dilakukan dengan baik. :-)
Jason S
1
@keyle Itu tergantung pada selfobjek akan pergi sebagai parameter pertama dan nilai propertinya.
Hydroper
8
Sintaks @keyle Colon akan sedikit lebih cepat jika objek yang Anda panggil bukan lokal, karena mesin virtual hanya mengambilnya sekali. Pada dasarnya, sintaks dot suka object.method(object,args)mengambil objectdua kali, sedangkan hanya object:method(arg)mengambil objectsekali. Jika objectadalah bidang global, peningkatan nilai atau tabel, maka :lebih cepat dari .. .tidak pernah lebih cepat dari :.
negamartin
28

Untuk definisi itu persis sama dengan menentukan sendiri secara manual - itu bahkan akan menghasilkan bytecode yang sama pada kompilasi. Yaitu function object:method(arg1, arg2)sama dengan function object.method(object, arg1, arg2).

Penggunaan :adalah hampir sama dengan .- jenis khusus dari panggilan akan digunakan secara internal untuk memastikan objectdan setiap kemungkinan efek samping dari perhitungan / akses dihitung hanya sekali. Panggilannya object:method(arg1, arg2)sama dengan object.method(object, arg1, arg2).

Oleg V. Volkov
sumber
21

Untuk sepenuhnya tepat, obj:method(1, 2, 3)sama dengan

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

Mengapa variabel lokal? Karena, seperti yang telah ditunjukkan banyak orang, obj:method()hanya indeks yang _ENVmendapatkan sekali obj. Ini biasanya hanya penting ketika mempertimbangkan kecepatan, tetapi pertimbangkan situasi ini:

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

Sekarang bayangkan __indexmetametode melakukan lebih dari sekedar mencetak sesuatu. Bayangkan itu meningkatkan penghitung, mencatat sesuatu ke file atau menghapus pengguna acak dari database Anda. Ada perbedaan besar antara melakukan itu dua kali atau hanya sekali. Dalam hal ini, ada perbedaan yang jelas antara obj.method(obj, etc)dan obj:method(etc).

DarkWiiPlayer
sumber
Anda benar-benar tidak perlu khawatir tentang hal-hal seperti itu. Jika Anda harus, ada sesuatu yang sangat salah dengan arsitektur Anda.
val berkata Reinstate Monica
2
Saya akan mengatakan sebaliknya; kode yang baik tidak boleh membuat asumsi tentang detail implementasi kode yang tidak terkait. Panggilan fungsi mungkin atau mungkin tidak memo, itu tidak berarti itu praktik yang baik untuk memanggil mereka lebih sering daripada yang dibutuhkan.
DarkWiiPlayer