2012-03-08 56 views
5

Tôi đang cố gắng hiểu chức năng này hoạt động như thế nào. bất cứ ai có thể giải thích điều này với tôi?Cố gắng hiểu đoạn mã lua này

function newInstance (class) 
    local o = {} 
    setmetatable (o, class) 
    class.__index = class 
    return o 
end 

Nó được gọi như thế này:

self = newInstance (self) 
+0

Xin vui lòng ai đưa ra một tiêu đề tốt hơn cho câu hỏi này vì tôi nghĩ rằng nó sẽ giúp số nhà phát triển ra khỏi đó. – chchrist

Trả lời

6

Chức năng này dường như đóng vai trò cung cấp một biến thể của OOP trong Lua (một chút cẩu thả trong quan điểm của tôi).

Đây là nhà máy của một lớp học.

Nó có thể được viết lại như sau, cho rõ ràng:

C = { } 

C.foo = function(self) -- just some method, so class would not be empty 
    print("foo method called", tostring(self)) 
end 

C.__index = C -- (A) 

function newInstance(class) 
    return setmetatable({ }, class) -- (B) 
end 

Bây giờ nếu chúng ta tạo ra hai trường hợp mới của C, chúng ta thấy rõ rằng cả hai đều có một foo() phương pháp, nhưng tự khác nhau:

o1 = newInstance(C) 
o1:foo() --> foo method called table: 0x7fb3ea408ce0 

o2 = newInstance(C) 
o2:foo() --> foo method called table: 0x7fb3ea4072f0 

các phương pháp foo đều giống nhau:

print(o1.foo, o2.foo, o1.foo == o2.foo and "equal" or "different") 
--> function: 0x7fb3ea410760 function: 0x7fb3ea410760 equal 

Điều này là do bảng C (các "lớp") là một __index ((A) ở trên) của metatable của o1o2, được đặt trong (B). Nhưng o1o2 thực sự là hai bảng khác nhau, được tạo tại (B) ("phiên bản lớp" hoặc "đối tượng").

Lưu ý: chúng tôi đặt C.__index bằng C chính nó tại (A) vì vậy chúng tôi sẽ sử dụng lại một bảng. Sau đây có tác dụng tương tự:

prototype = { } 

prototype.foo = function(self) -- just some method, so class would not be empty 
    print("foo method called", tostring(self)) 
end 

C = { __index = prototype } 

function newInstance(class) 
    return setmetatable({ }, class) 
end 

o = newInstance(C) 
1

Điều này được sử dụng để đạt được hành vi hướng đối tượng trong Lua. Lua sử dụng kế thừa dựa trên nguyên mẫu (tương tự như Javascript) thay vì thừa kế dựa trên lớp (như Java hoặc C++). Ý tưởng là tất cả các phương thức lớp được thực hiện như là một phần của một đối tượng nguyên mẫu và kế thừa các đối tượng ủy nhiệm cho nguyên mẫu khi có cuộc gọi.

Ví dụ, giả sử bạn muốn có một lớp myClass cung cấp một phương pháp getMagicNumber:

local myClass = { 
    getMagicNumber = function(self) 
     return self.theNumber; 
    end }; 

local obj = newInstance(myClass); 
obj.theNumber = 42; 
print(obj:getMagicNumber()); -- supposed to return 42 

Đó là loại một ví dụ nhỏ, nhưng tôi hy vọng bạn sẽ có được ý tưởng. Điều gì xảy ra là điều này: newInstance tạo một bảng mới với chỉ số có thể chỉnh sửa của nó trỏ đến myClass và cũng đảm bảo rằng trường __index của các điểm có thể so sánh với myClass. Khi hướng dẫn Lua trên __index mô tả, khi bạn cố gắng gọi hàm getMagicNumber trên bảng mới đó, điều sau sẽ xảy ra: Lần đầu tiên Lua tìm trường getMagicNumber trong bảng obj. Vì bảng đó trống, mặc dù bây giờ nó tìm kiếm bảng __index của nó (myClass) cho trường đó. Kể từ khi trường được tìm thấy ở đó, nó bây giờ gọi hàm được tìm thấy trong myClass.

Programming in Lua thảo luận về cơ chế này một cách chi tiết nếu bạn cần biết thêm.

1

Bạn không đơn độc, tôi mất một chút thời gian để bẻ mã này.Dưới đây là giải thích của tôi

mỗi bảng có thể có netatable, metatable có thể lưu trữ trong số các chức năng khác được lập chỉ mục theo tên, và setmetatable đặt giá trị của metatable đủ tự nhiên.

Dòng line._index = .. là nơi phép thuật xảy ra.

Khi bạn cố gắng gọi hàm bằng self.fn1(), thì lua tra cứu trong tên tự fn1. Nếu nó không thể tìm thấy nó sau đó nó trông trong tự metatable cho một bảng __index, và tìm một 'fn1' trong bảng được lưu trữ ở đó.

Bây giờ metatable cho self trong ví dụ của bạn là class, vì vậy lua tìm kiếm một entry __index trong metatable (class) để xem có hàm nào có tên là fn1 trong bảng đó hay không. Bạn cần phải thiết lập __index cho lớp trở lại chính nó để lua sẽ xem xét trong cùng một metatable - khó hiểu hey.

(như một sự phân công sang __index chỉ cần xảy ra một lần, nhưng vì lý do nào đó nó luôn được thực hiện trong toán tử mới trong tất cả các ví dụ lua - tôi mang nó ra ngoài lớp mới trong lớp của tôi - tiết kiệm một vài chu kỳ)

Sau đó bạn trả lại bảng mới o, lua là rác được thu thập để trả về một địa phương tạo một bảng mới mỗi lần.

function newInstance (class) 
    local o = {} 
    setmetatable (o, class) 
    class.__index = class 
    return o 
end 

hth

Các vấn đề liên quan