闭包分析:lua function,oc 代码块可以产生闭包.c++lambda不能产生闭包

什么是闭包?这个问题说简单挺简单的,但是一般讲了之后跟没讲一样。就拿下面的lua代码看一下。

local function getCallBack()
	local x = 1
	return function()
		x = x + 1
		print(x)
	end
end

local fun = getCallBack()
fun()
fun()
fun()

上面的fun获得的就是一个闭包,虽然获取的只是一个函数,但是它包含了getCallBack里的变量x,x我们称之为upvalue。很奇怪吧,getCallBack调用完,理论上它分配的栈会被回收,x也会被清除了,可是fun这个函数变量将会一直把持x。为什么fun一直能把持x呢?getCallBack在return之前,它应该把x压入了调用它的函数的栈中了,return时再把函数地址压入栈中,x与这个函数地址值构成了一个闭包形成一个整体。而调用这个闭包中函数时,先在此函数作用域找x,由于找不到,然后到它的闭包环境中去找。上面fun的输出是2、3、4,因为x一直保存在闭包环境中,每次调用x加一

下面是闭包英文解释,讲的就是闭包是使用了自由的变量,使用自由变量这话完全听不懂,太玄乎,不自由变量是什么?大家只知道静态变量,常变量,局部变量什么的,这个还真没听过。不过后面一句话说的很清楚,闭包是在闭包成员环境中创建的,闭包是一组环境变量加一个函数,此函数可以访问这些变量。这些变量lua里称为upvalue

Closures are functions that refer to independent (free) variables. In other words, the function defined in the closure'remembers' the environment in which it was created.


oc里的代码块也产生闭包,下面定义了一个代码块block。传到闭包环境中的变量默认是常量,只能访问,不能修改的,要想修改必须在变量声明前加上__block。

int a = 3;
int b = 5;
    
void (^block)() = ^(){printf("%d %d\n", a, b);};
block();
上面代码还不能说明产生了闭包,下面代码跟开头的lua代码功效一样输出是2、3、4,可以看出是个闭包。先声明block类型,然后创建getBlock函数,它返回的是一个闭包,x在这个闭包环境中。__block指示了x可以被修改,闭包中函数每次调用加一并且输出x的值。

typedef void(^block)();

block getBlock(){
    __block int x = 1;
    return ^(){
        x += 1;
        printf("%d\n", x);
    };
}

int main(int argc, const char * argv[]) {
    block b = getBlock();
    b();
    b();
    b();
}


c++中的lambda表达式产生不了闭包,看起来能。。。,下面是lambda的定义

 [capture list] (parameter list) ->return type { function body }

下面是一个例子,[]中的是捕获列表,lua里传入闭包环境中的变量可读写,都是直接对变量本身操作,没有中间变量作为参数。oc中默认传入的是常量,只读,通过__block关键字可以设置为可写。而c++默认传入闭包环境的也是常量,你要想修改这些变量,需要在想修改的变量前加&,如果像下面一样就是所有传入闭包的都可以修改。上面lambda的定义很清晰了,就不解释了。
  auto lam =  [&]()->int {
        return 50;
    };

下面代码的输出是 32768、 32768、 32768,显然x没有被加入到闭包环境中,也就说明闭包根本不存在

std::function<void(void)> get(){
    int x = 0;
    return [&]()->void{
        x += 1;
        printf("%d\n", x);
    };
}

int main(int argc, const char * argv[]) {
    auto fun = get();
    fun();
    fun();
    fun();
}

总的说来,闭包有利也有弊,并不鼓励过多使用,用的太多了逻辑会变混乱,后期维护也会变麻烦。闭包的后面其实是函数对象这个东西,在lua里,js里函数对象也是基本类型,用起来得心应手,而编译型的高级语言一般很少提供的,不过现在许多都提供了类似类型,oc使用了代码块,java、c++都加入lamdba大军了。不知道函数式编程是种什么体验,有时间好好专研下,不知道跟函数对象有什么关联。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值