您的位置:首页 > 编程语言 > Lua

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

2016-03-16 17:25 375 查看
什么是闭包?这个问题说简单挺简单的,但是一般讲了之后跟没讲一样。就拿下面的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大军了。不知道函数式编程是种什么体验,有时间好好专研下,不知道跟函数对象有什么关联。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: