Sự khác biệt giữa . và: ở Lua


174

Tôi bối rối về sự khác biệt giữa các cuộc gọi chức năng thông qua .và thông qua:

> 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

Đang :làm gì vậy


Câu trả lời:


237

Dấu hai chấm là để thực hiện các phương thức vượt qua selfnhư là tham số đầu tiên. Vì vậy, x:bar(3,4)nên giống như x.bar(x,3,4).


55
ah ... vậy đó là đường cú pháp hướng đối tượng.
Jason S

7
Chính xác. Trong toàn bộ tài liệu tham khảo, lời giới thiệu duy nhất họ đưa ra về điều này là "Cú pháp dấu hai chấm được sử dụng để xác định các phương thức, nghĩa là, các hàm có một tham số phụ ẩn." (Hướng dẫn 5.0, dưới cùng của trang pdf 19)
BMitch

2
ooh ahh ... Tôi sẽ hỏi tài liệu chính thức về vấn đề này ở đâu, nhưng bạn đã đánh bại tôi. độc đáo thực hiện. :-)
Jason S

1
@keyle Nó phụ thuộc vào selfđối tượng sẽ là tham số đầu tiên và giá trị thuộc tính của nó.
Hydroper

8
@keyle Cú pháp đại tràng sẽ nhanh hơn một chút nếu đối tượng bạn gọi không phải là cục bộ, vì máy ảo chỉ truy xuất nó một lần. Về cơ bản, cú pháp chấm như object.method(object,args)lấy objecthai lần, trong khi chỉ object:method(arg)lấy objectmột lần. Nếu objectlà trường toàn cầu, giá trị tăng hoặc bảng, thì :nhanh hơn .. .không bao giờ là nhanh hơn :.
negamartin

28

Đối với định nghĩa, nó hoàn toàn giống với việc chỉ định tự thủ công - thậm chí nó sẽ tạo ra cùng một mã byte khi biên dịch. Tức function object:method(arg1, arg2)là giống như function object.method(object, arg1, arg2).

Về sử dụng :gần như giống như .- một loại đặc biệt của cuộc gọi sẽ được sử dụng trong nội bộ để đảm bảo objectvà bất kỳ tác dụng phụ có thể có của phép tính / truy cập được tính một lần duy nhất. Gọi object:method(arg1, arg2)là khác như object.method(object, arg1, arg2).


21

Hoàn toàn chính xác, obj:method(1, 2, 3)giống như

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

Tại sao biến cục bộ? Bởi vì, như nhiều người đã chỉ ra, obj:method()chỉ lập chỉ mục _ENVmột lần để có được obj. Điều này thường chỉ quan trọng khi xem xét tốc độ, nhưng xem xét tình huống này:

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

Bây giờ hãy tưởng tượng __indexmetamethod đã làm nhiều hơn là chỉ in một cái gì đó. Hãy tưởng tượng nó tăng một bộ đếm, ghi lại một cái gì đó vào một tập tin hoặc xóa một người dùng ngẫu nhiên khỏi cơ sở dữ liệu của bạn. Có một sự khác biệt lớn giữa việc làm điều đó hai lần hoặc chỉ một lần. Trong trường hợp này, có một sự khác biệt rõ ràng giữa obj.method(obj, etc)obj:method(etc).


Bạn thực sự không nên lo lắng về những thứ như vậy. Nếu bạn phải, có một cái gì đó cực kỳ sai với kiến ​​trúc của bạn.
val nói Phục hồi lại

2
Tôi muốn nói đó là cách khác; mã tốt không nên đưa ra bất kỳ giả định nào về chi tiết triển khai của mã không liên quan. Các cuộc gọi chức năng có thể hoặc không thể được ghi nhớ, điều đó không có nghĩa là thực hành tốt để gọi chúng thường xuyên hơn mức cần thiết.
DarkWiiPlayer
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.