Lua function closures

lua的函数为数据类型之一, 也叫first-class.
所以可以把函数赋予给变量, 这个我在前一篇BLOG中写过, 例如
function f(x) return x*2 end
和f = function(x) return x*2 end
是一样的写法.
甚至可以把函数作为返回值, 例如 :
function f(x) 
  return function (x) return x*2 end 
end

这里其实返回了一个匿名函数,
a = f(1)
> a = f(1)
> = a
function: 0x12a0ab0
> =a(1)
2
> return a(2)
4

那么什么是closure呢?
我们来看一个函数 :
function newc()
  local i = 0  
  return function ()
    i = i+1  -- 非本地, 非全局, 函数中的函数可以访问它上层的本地变量, 并可以逃逸这个变量, 成为一个非本地, 非全局变量.
    return i
  end
end

这个函数返回一个函数, 在返回的匿名函数中, i其实是newc函数的本地变量, 对匿名函数来说, i变量非本地, 非全局.
那么把newc()的结果匿名函数赋予给一个变量后, i就变成了这个函数的一部分, 
closure包含"函数的定义"以及"函数需要访问的非本地, 非全局变量, 这个例子是i".
我们可以理解为closure实际上包含了两部分信息, 一部分是定义区域, 一部分是函数自有的变量区域(非本地, 非全局.)
利用这种方式创建的函数, 自由变量可以用作计数器, 例如 :
> c1 = newc()
> = c1
function: 0x1291a70
> return  c1()  -- i这个自由变量在当前这个c1函数/closure内自增.
1
> return  c1()
2
> return  c1()
3
> c2 = newc()
> = c2   -- i这个自由变量在当前这个c2函数/closure内自增. 和c1/closure没有关系.
function: 0x12a2290
> return  c2()
1
> return  c2()
2
> return  c1()
4


由于函数名只是一个closure的名称, 所以可以很方便的复写. 例如
> do 
  local oldsin = math.sin  -- 把math.sin这个函数名指向的closure赋予给本地变量oldsin. 对外就隐藏了
  local k = math.pi/180  
  math.sin = function(x)    -- 复写math.sin
    return oldsin(x*k)
  end
end

那么以后调用math.sin就是新的closure了, 老的closure因为被指向为一个本地变量, 已经无法被使用了.
> = oldsin(1)
stdin:1: attempt to call global 'oldsin' (a nil value)
stack traceback:
        stdin:1: in main chunk
        [C]: in ?
> = math.sin(1)
0.00030461741507571

这种用法类似黑盒, 把一个closure隐藏, 对外使用新的一个closure.
还有一个例子是对文件操作加一个权限判断, 隐藏没有权限判断的io.open函数.
> do 
  local oldopen = io.open  -- 把老的io.open存储到一个本地变量, 对外隐藏.
  local access_ok = function (filename, mode)  -- 权限判断函数
     -- check access, return boolean
    end
  io.open = function (filename, mode)  -- 复写io.open
    if access_ok(filename, mode) then
      return oldopen(filename,mode)  -- 在黑盒中访问外部的本地变量oldopen, 这个新的io.open函数/closure包含了oldopen这个变量.
    else
      return nil, "access denied"
    end
  end
end

-- 那么以后调用io.open时其实调用的是复写的io.open.

小结.
1. Lua函数或closure的一个重大功能是, 对上层函数的本地变量的可访问, 以及逃逸(逃逸这个说得明白点就是closure中包含变量信息, 同时包含定义信息).
2. 支持复写, 同时结合本地变量的逃逸, 很好的达到黑盒目的.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值