2010-12-11 38 views
5

Tôi mới bắt đầu với Lua. Trong ví dụ tôi đang học từ (the Ghosts & Monsters Corona open source), tôi thấy mẫu này lặp đi lặp lại.Sự khác biệt giữa hai ví dụ Lua này là gì? Là một tốt hơn?

local director = require("director") 

local mainGroup = display.newGroup() 

local function main() 

    mainGroup:insert(director.directorView) 

    openfeint = require ("openfeint") 
    openfeint.init("App Key Here", "App Secret Here", "Ghosts vs. Monsters", "App ID Here") 

    director:changeScene("loadmainmenu") 

    return true 
end 

main() 

Đây có phải là một loại quy ước mà các lập trình viên Lua có kinh nghiệm đề xuất hoặc có lợi thế chính hãng để thực hiện theo cách này không? Tại sao bạn không bỏ qua chức năng này cùng nhau và thực hiện điều này:

local director = require("director") 

local mainGroup = display.newGroup() 

mainGroup:insert(director.directorView) 

local openfeint = require ("openfeint") 
openfeint.init("App Key Here", "App Secret Here", "Ghosts vs. Monsters", "App ID Here") 

director:changeScene("loadmainmenu") 

Có lợi ích ngầm định nào cho kiểu đầu tiên trong giây lát không? Cảm ơn!

+0

Bạn có chắc chắn đã đơn giản hóa nó đúng cách không? Bạn có thể liên kết với một số ví dụ này dưới dạng đầy đủ của họ không? – Amber

+1

Vâng, 'mẫu' bạn đã đăng có vẻ hoàn toàn vô nghĩa. Bạn nói rằng bạn thấy rằng "rất nhiều", bạn có thể liên kết với một ví dụ? – Mud

+0

Tôi đã chỉnh sửa câu hỏi với một ví dụ hoàn chỉnh hơn và được trích dẫn nơi bạn có thể tải xuống bản lưu trữ nguồn hoàn chỉnh. Nếu Lua giống như các ngôn ngữ khác tôi biết, có vẻ như hình thức thứ 2 làm nhiều hơn với ít hơn. –

Trả lời

8

Đây có phải là một số loại quy ước mà các lập trình viên Lua có kinh nghiệm đề xuất hoặc có lợi thế chính hãng để thực hiện theo cách này không?

Nó không phải là điển hình. Ưu điểm là trạng thái đối tượng là riêng tư, nhưng đó không đủ lợi thế để giới thiệu nó.

Tôi thấy mẫu này nhiều lần.

Tôi chưa bao giờ thấy trước đây và chỉ xảy ra một lần trong nguồn bạn đã đăng.

CHỈNH SỬA: Thêm câu trả lời cho câu hỏi được hỏi trong các nhận xét bên dưới bài đăng này.

Chức năng truy cập các biến cục bộ bên ngoài liên kết với các biến đó và được gọi là 'đóng cửa'. Lua (vì lý do lịch sử) đề cập đến những biến ràng buộc đó là 'upvalues'. Ví dụ:

local function counter() 
    local i = 1 
    return function() 
     print(i) 
     i = i + 1 
    end 
end 

local a, b = counter(), counter() 
a() a() a() b() --> 1 2 3 1 

ab đang đóng cửa ràng buộc để bản khác nhau của i, như bạn có thể nhìn thấy từ đầu ra. Nói cách khác, bạn có thể nghĩ về việc đóng cửa như một chức năng với trạng thái riêng tư của nó. Bạn có thể sử dụng để mô phỏng các đối tượng:

function Point(x,y) 
    local p = {} 
    function p.getX() -- syntax sugar for p.getX = function() 
     return x 
    end 
    function p.setX(x_) 
     x = x_ 
    end 
    -- for brevity, not implementing a setter/getter for y 
    return p 
end 

p1 = Point(10,20) 
p1.setX(50) 
print(p1.getX()) 

Point trả về một bảng đóng cửa, mỗi ràng buộc với người dân địa phương xy. Bảng này không chứa trạng thái của điểm, bản thân các đóng bao làm, thông qua upvalues ​​của họ. Một điểm quan trọng là mỗi lần Point được gọi là nó tạo ra đóng cửa mới, không hiệu quả lắm nếu bạn có số lượng lớn đối tượng.

Một cách khác để tạo ra các lớp học trong Lua là để tạo ra các chức năng mà phải mất một bảng như là đối số đầu tiên, với trạng thái được lưu trữ trong bảng:

function Point(x,y) 
    local p = {x=x,y=y} 
    function p:getX() -- syntax sugar for p.getX = function(self) 
     return self.x 
    end 
    function p:setX(x) 
     self.x = x 
    end 
    return p 
end 

p1 = Point(10,20) 
p1:setX(50) -- syntax sugar for p1.setX(p1, 50) 
print(p1:getX()) -- syntax sugar for p1.getX(p1) 

Cho đến nay, chúng tôi vẫn tạo ra các bản sao mới của mỗi phương pháp, nhưng bây giờ mà chúng ta không dựa vào upvalues ​​cho nhà nước, chúng ta có thể khắc phục điều đó:

PointClass = {} 
function PointClass:getX() return self.x end 
function PointClass:setX(x) self.x = x end 
function Point(x,y) 
    return { 
     x = x, 
     y = y, 
     getX = PointClass.getX, 
     setX = PointClass.getY, 
    } 
end 

Bây giờ các phương pháp được tạo ra một lần, và tất cả các trường hợp Point chia sẻ việc đóng cửa tương tự. Một cách tốt hơn để làm điều này là sử dụng cơ sở lập trình meta Lua để làm mới Point trường tự động tìm trong PointClass vì đã không tìm thấy phương pháp trong trường hợp bản thân:

PointClass = {} 
PointClass.__index = PointClass -- metamethod 
function PointClass:getX() return self.x end 
function PointClass:setX(x) self.x = x end 
function Point(x,y) 
    return setmetatable({x=x,y=y}, PointClass) 
end 

p1 = Point(10,20) 
-- the p1 table does not itself contain a setX member, but p1 has a metatable, so 
-- when an indexing operation fails, Lua will look in the metatable for an __index 
-- metamethod. If that metamethod is a table, Lua will look for getX in that table, 
-- resolving p1.setX to PointClass.setX. 
p1:setX(50) 

Đây là một cách nhiều thành ngữ của việc tạo ra các lớp học trong Lua. Đó là bộ nhớ hiệu quả hơn và linh hoạt hơn (đặc biệt, nó làm cho nó dễ dàng để thực hiện kế thừa).

+0

Bùn, nó xuất hiện một lần trong tập tin cụ thể đó (main.lua) nhưng tác giả sử dụng mẫu trên toàn bộ mã. Nhiều tệp trong tệp lưu trữ (cấp * .lua, tải * .lua,) sử dụng mẫu này. Điều đó nói rằng, director.lua được bao gồm trong kho lưu trữ nhưng được viết bởi một tác giả khác dường như không có khuôn mẫu - điều này dẫn tôi đến việc tin rằng đó là phong cách của tác giả Ghosts & Monster. –

+0

Vâng, đó là điều của anh ta. Các mã nói chung không phải là rất thành ngữ Lua. Đặc biệt, phương pháp tạo các lớp của anh ta rất khác thường: tạo ra một đóng mới cho mọi phương thức instance, lưu trữ trạng thái trong upvalue, thay vì một tập các phương thức chia sẻ cho lớp với trạng thái được lưu trữ trong các bảng. Điều này là khá lãng phí, nhưng nó cũng là một cách để tạo ra trạng thái thực sự riêng tư. Điều đó * có thể * là những gì anh ta làm, nhưng sau đó có các khu vực khác của mã nơi anh ta sử dụng các bảng cho nhà nước (đôi khi cùng một lớp lưu trữ một phần của trạng thái của nó trong upvalues, và một phần trong một bảng). – Mud

+0

Bùn, cảm ơn cho cuộc thảo luận. Một lần nữa, kể từ khi tôi mới đến Lua, bạn có nhớ giải thích những gì bạn có nghĩa là bằng upvalues? Cảm ơn! –

0

Tôi không thấy nhiều điểm đến kiểu đầu tiên như bạn đã thể hiện. Nhưng nếu nó nói một cái gì đó như if arg then main() end ở phía dưới, kịch bản có thể (chỉ có thể) có ích như là một "thư viện" có thể nạp được ngoài việc là một tập lệnh độc lập. Điều đó nói rằng, có một main() giống như những mảnh vỡ của C, không phải Lua; Tôi nghĩ bạn đúng khi đặt câu hỏi đó.

3

tôi thường xuyên viết kịch bản Lua riêng tôi theo cách này vì nó cải thiện khả năng đọc trong trường hợp này:

function main() 
    helper1(helper2(arg[1])) 
    helper3() 
end 

function helper1(foo) 
    print(foo) 
end 

function helper2(bar) 
    return bar*bar 
end 

function helper3() 
    print('hello world!') 
end 

main() 

Bằng cách này, "chính" đang ở phía trên, nhưng tôi vẫn có thể xác định các chức năng toàn cầu cần thiết trước khi nó thực hiện.

Một mẹo đơn giản, thực sự. Tôi không thể nghĩ ra bất kỳ lý do nào để làm điều này ngoài khả năng đọc được.

1

Kiểu đầu tiên có thể được sử dụng quá thay đổi khả năng đọc, nhưng tôi muốn cung cấp cho hàm một số tên có ý nghĩa thay vì chính hoặc chỉ cần không có chức năng.

Nhân tiện, tôi nghĩ rằng luôn luôn thực hành tốt để đặt tên cho các khối mã, tức là đặt chúng vào các hàm hoặc phương thức. Nó giúp giải thích ý định của bạn với đoạn mã đó và khuyến khích tái sử dụng.

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