我刚刚开始使用Lua.在我正在学习的例子中(Ghosts&Monsters Corona开源),我反复看到这种模式.
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()
Run Code Online (Sandbox Code Playgroud)
这是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" )
Run Code Online (Sandbox Code Playgroud)
第二种风格对第一种风格有一些隐含的好处吗?谢谢!
这是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
Run Code Online (Sandbox Code Playgroud)
a
并且从输出中可以看到b
绑定到不同副本的闭包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())
Run Code Online (Sandbox Code Playgroud)
Point
返回一个闭包表,每个闭包都绑定到本地x
和y
.该表不包含点的状态,闭包本身通过它们的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)
Run Code Online (Sandbox Code Playgroud)
到目前为止,我们仍然在创建每个方法的新副本,但是现在我们不依赖于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
Run Code Online (Sandbox Code Playgroud)
现在,方法创建一次,并且所有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)
Run Code Online (Sandbox Code Playgroud)
这是在Lua中创建类的更惯用的方式.它的内存效率更高,更灵活(特别是它可以轻松实现继承).