关于Lua中“关闭”的一些问题

时间:2011-08-04 02:02:02

标签: lua closures

这是我的代码,我把返回函数(c1,c2)中的局部变量'count'与内存strack混淆,它们存储在哪里?

function make_counter()
  local count = 0
  return function()
    count = count + 1
    return count
  end
end
c1 = make_counter()
c2 = make_counter()
print(c1())--print->1
print(c1())--print->2
print(c1())--print->3

print(c2())--print->1
print(c2())--print->2

3 个答案:

答案 0 :(得分:4)

  

在具有内存条件的返回函数(c1,c2)中它们存储在哪里?

它存储在封闭中!

c1不是闭包,它是make_counter()返回的函数。闭包没有在任何地方明确声明。它是make_counter()返回的函数与该函数的“自由变量”的组合。请参阅closures @ Wikipedia,特别是implementation

  

闭包通常使用特殊的数据结构实现,该结构包含指向函数代码的指针,以及创建闭包时函数的词法环境(例如,可用变量及其值的集合)的表示。

答案 1 :(得分:2)

我不太清楚你究竟在问什么,但我会尝试解释闭包是如何工作的。

在Lua中执行此操作时:

function() <some Lua code> end

您正在创建。值类似于数字1,字符串“string”等等。

不可变。例如,数字1始终是数字1.它永远不能是数字2。您可以添加1到2,但这将为您提供一个新的数字3.字符串也是如此。字符串“string”是一个字符串,并且始终是该特定字符串。您可以使用Lua函数来删除字符串中的所有“g”字符,但这会创建一个 new 字符串“strin”。

函数是,就像数字1和字符串“string”一样。值可以存储在变量中。您可以将数字1存储在多个变量中。您可以将字符串“string”存储在多个变量中。所有其他类型的值都是如此,包括函数。

函数是值,因此它们是不可变的。但是,函数可以包含值;这些值不可变。这很像桌子。

{}语法创建一个Lua表,它是一个值。此表与其他每个表都不同,甚至是其他空表。但是,您可以在表格中添加不同的内容。这不会更改表的唯一值,但会更改该表中存储的内容。每次执行{}时,您都会获得一个新的唯一表。所以如果你有以下功能:

function CreateTable()
    return {}
end

以下情况属实:

tableA = CreateTable()
tableB = CreateTable()
if(tableA == tableB) then
    print("You will never see this")
else
    print("Always printed")
end

即使tableAtableB都是空表(包含相同的内容),它们也是不同的表。它们可能包含相同的内容,但它们的值不同。

功能也是如此。 Lua中的函数通常称为“闭包”,特别是如果函数具有内容。函数根据它们如何使用变量给出内容。如果函数引用了创建该函数的位置范围内的局部变量(请记住:每次调用它时语法function() end都会创建一个函数),那么函数将会包含对该局部变量的引用。

但局部变量超出范围,而函数的值可能存在(在您的情况下,您返回它)。因此,函数的对象(闭包)必须包含对该局部变量的引用,该引用将使其继续存在,直到关闭本身被丢弃。

值存储在哪里?没关系;只有闭包可以访问它们(虽然有一种方法可以通过C Lua API,或通过Lua Debug API)。因此,与表格不同的是,您可以获得所需的任何内容,闭包可以真正隐藏数据。

答案 2 :(得分:0)

Lua Closures也可用于实现基于原型的类和对象。闭包类和对象的行为与普通的Lua类略有不同,它们的调用方法有所不同:

-- closure class definition

StarShip = {}

function StarShip.new(x,y,z)
    self = {}

    local dx, dy, dz
    local curx, cury, curz
    local engine_warpnew

    cur_x = x; cur_y = y; cur_z = z

    function setDest(x,y,z)
        dx = x; dy=y; dz=z;
    end

    function setSpeed(warp)
        engine_warpnew = warp
    end

    function self.warp(x,y,z,speed)
        print("warping to ",x,y,x," at warp ",speed)
        setDest(x,y,z)
        setSpeed(speed)
    end

    function self.currlocation()
        return {x=cur_x, y=cur_y, z=cur_z}
    end

    return self
end

enterprise = StarShip.new(1,3,9)

enterprise.warp(0,0,0,10)

loc = enterprise.currlocation()

print(loc.x, loc.y, loc.z)

产生以下输出:

在经线10处扭曲到0 0 0 1 3 9

这里我们将原型对象“StarShip”定义为空表。

然后我们在“new”方法中为StarShip创建一个构造函数。它做的第一件事是创建一个名为self的闭包表,其中包含对象的方法。闭包中的所有方法(定义为'function self。')都是“闭合的”或为构造函数可访问的所有值定义。这就是它被称为闭包的原因。当构造函数完成时,它返回闭包对象“return self”。

有关基于闭包的对象的更多信息,请点击此处:

http://lua-users.org/wiki/ObjectOrientationClosureApproach