这两个Lua示例之间有什么区别?一个更好吗?

时间:2010-12-11 22:38:44

标签: lua

我刚刚开始使用Lua。在我从(the Ghosts & Monsters Corona open source)学习的例子中,我反复看到这种模式。

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

第二种风格对第二种风格有一些隐含的好处吗?谢谢!

4 个答案:

答案 0 :(得分: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时,它都会创建 new 闭包,如果你有大量的对象,效率不高。

在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 for state,我们可以解决这个问题:

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中创建类的更惯用的方法。它的内存效率更高,更灵活(特别是它可以很容易地实现继承)。

答案 1 :(得分: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()

这样“主”代码位于顶部,但我仍然可以在执行之前定义必要的全局函数。

一个简单的伎俩,真的。除了可读性之外,我想不出任何理由这样做。

答案 2 :(得分:1)

第一种风格可以用得太可读了,但我宁愿给这个函数一些有意义的名字,而不是 main ,或者只是没有这个功能。

顺便说一句,我认为命名代码块总是一个好习惯,即将它们放入函数或方法中。它有助于解释您对该段代码的意图,并鼓励重用。

答案 3 :(得分:0)

我没有看到你所展示的第一种风格。但如果它在底部说了if arg then main() end之类的东西,那么除了作为一个独立的脚本之外,该脚本可能(只是可能)可用作可加载的“库”。也就是说,有一个main()那样的C,而不是Lua;我认为你提出质疑是正确的。