2010-12-11 48 views
5

我剛剛開始使用Lua。在我學習的例子中(the Ghosts & Monsters Corona open source),我反覆看到這種模式。這兩個Lua例子有什麼區別?更好嗎?

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() 

這是某種約定的經歷的Lua編程建議還是有真正的優勢,做這種方式?你爲什麼不直接跳過這個功能,並且這樣做:

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") 

第二種方式對第一種方式有一些明顯的好處嗎?謝謝!

+0

你確定你已經簡化了它嗎?你能以完整的形式鏈接到這些例子嗎? – Amber 2010-12-11 22:51:32

+1

是的,你發佈的'模式'似乎完全沒有意義。你說你看到「很多」,你能鏈接到一個例子嗎? – Mud 2010-12-12 01:38:15

+0

我用一個更完整的例子編輯了這個問題,並引用了你可以下載完整的源代碼檔案的地方。如果Lua與我所知道的其他語言一樣,看起來第二種形式可以少花錢。 – 2010-12-12 04:33:47

回答

8

這是一種有約會經驗的Lua程序員推薦的方法嗎?還是有真正的優點來做到這一點?

這不是典型的。優點是對象狀態是私有的,但這不足以推薦它。

我反覆看到這種模式。

我從來沒有見過它,它只發生在您發佈的源中一次。

編輯:添加一個迴應問題在這篇文章下面的評論問。

訪問外部局部變量的函數將綁定到這些變量並稱爲'閉包'。 Lua(出於歷史原因)將這些約束變量稱爲「upvalues」。例如:

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被封鎖必然的i不同的副本,你可以從輸出中看到。換句話說,你可以將閉包看作是它自己的私有狀態的函數。你可以用它來模擬對象:

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返回關閉表,每個綁定當地人xy。該表不包含點的狀態,封閉本身通過它們的upvalues。重要的一點是,每次調用Point時,都會創建新的閉包,如果您擁有大量對象,則閉包效率不高。

在Lua創建類的另一種方法是創建存儲在表中使用表作爲第一個參數的功能,與國家:

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) 

到目前爲止,我們仍然創造的新副本每一種方法,但現在我們不依靠upvalues的狀態,我們可以解決這個問題:

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 

現在的方法是創建一次,所有Point實例共享相同的瓶蓋。這樣做的更好的方法是使用Lua的元編程設施,使新Point情況下自動尋找在PointClass在實例本身未找到方法:

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) 

這是在Lua創建類的更地道的方式。它具有更高的內存效率和更高的靈活性(特別是,它可以很容易地實現繼承)。

+0

泥,它在該特定文件(main.lua)中出現一次,但作者在整個代碼中使用該模式。檔案中的許多文件(level * .lua,load * .lua)都使用這種模式。也就是說,包含在檔案中但由不同作者撰寫的director.lua似乎沒有這種模式 - 這讓我相信它是鬼怪怪獸的作者風格。 – 2010-12-13 14:43:32

+0

是的,這是他的事。一般的代碼不是很習慣Lua。特別是,他創建類的方法非常不尋常:爲每個實例方法創建一個新的閉包,將狀態存儲在upvalues中,而不是爲存儲在表中的狀態存儲一組共享方法。這非常浪費,但它也是創建真正的私有狀態的一種方式。這*可能是他正在做的事情,但是在代碼的其他領域中,他使用表格來表示狀態(有時用相同的類將其狀態的一部分存儲在upvalues中,並且部分存儲在表中)。 – Mud 2010-12-14 03:50:53

+0

泥,感謝您的討論。再一次,因爲我是Lua新手,你會介意解釋你的意思嗎?謝謝! – 2010-12-15 14:57:44

0

我沒有看到你指出的第一種風格。但是如果它在底部說了類似if arg then main() end的東西,那麼除了作爲獨立腳本之外,該腳本可能(可能會)作爲可加載的「庫」是有用的。這就是說,有一個main()這樣的C,而不是Lua;我認爲你是對的。

3

我經常寫我自己的Lua腳本這種方式,因爲它在這種情況下,提高了可讀性:

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() 

這樣的「主」的代碼是在頂部,但我仍然可以前定義必要的全局函數它執行。

一個簡單的伎倆,真的。除了可讀性,我想不出任何理由來做這件事。

1

第一種風格可能會使用過於簡單易讀,但我寧願給這個功能一些有意義的名稱,而不是主要或只是沒有該功能。順便說一下,我認爲命名代碼塊總是一個很好的做法,即將它們放入函數或方法中。它有助於解釋你對這段代碼的意圖,並鼓勵重用。