闭包

闭包就是能够读取其他函数内部变量的函数,在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数”。

C#闭包

  • 闭包是一个代码块(在C#中,指的是匿名方法或者Lambda表达式,也就是匿名函数),并且这个代码块使用到了代码块以外的变量,于是这个代码块和用到的代码块以外的变量(上下文)被“封闭地包在一起”。
  • 当使用此代码块时,该代码块里使用的外部变量的值,是使用该代码块时的值,并不一定是创建该代码块时的值。
  • 正常的函数内部的变量是保存在帧栈中(call stack>record Frame)。
  • 当形成闭包以后托管堆就形成一个类用来存放该变量
  • 一句话概括,闭包是一个包含了上下文环境的匿名函数。
//闭包中内层的函数可以引用包含在它外层函数的变量,即使外层函数的执行已经终止
//该变量提供的值并非变量创建时候的值,而是在父函数范围内的最终值
class Test
{
    public event Action action;
    //构造函数
    public Test()
    {
        //value如果没有下面的引用,应该在执行完构造函数就被gc掉
        int value = 10;
        //这里就形成了闭包,因为当构造函数执行后,其中申明的临时变量value的生命周期被改变了
        action = () =>
        {
            Console.WriteLine(value);
        }
        //该变量提供的值并非变量创建时候的值,而是在父函数范围内的最终值
        for (int i = 0; i < 10; i++)
        {
            action += () =>
            {
                Console.WriteLine(i);
            }
	}
    }
    public void DoSomething()
    {
        action();
    }
}
//执行DoSomething(),外部输出11个10

Lua闭包

什么是闭包

--嵌套函数
function fun9(x)
	-- 在函数内部再声明一个函数,会改变外部函数传入参数的生命周期,从而产生了一个闭包
	-- 此处x的生命周期就被延长了
	return function(y)
		print(x + y)
	end
end
fun10 = fun9(5)  -- 此处传入的5的生命周期被延长了,在fun10中仍需要使用
fun10(2)  
-- 输出7

闭包的数据共享

function shareVar(n)
  local function func1()
    print(n)
  end

  local function func2()
    n = n + 10
    print(n)
  end
  return func1,func2
end

local f1,f2 = shareVar(1024) --创建闭包,f1,f2两个闭包共享同一份upvalue

f1() -- 输出1024
f2() -- 输出1034
f1() -- 输出1034
f2() -- 输出1044

闭包的数据隔离

function counter()
  local i = 0
  return function() --匿名函数,闭包
    i = i + 1
    return i
  end
end

counter1 = counter()
counter2 = counter() 
-- counter1,counter2 是建立在同一个函数,同一个局部变量的不同实例上面的两个不同的闭包
--                   闭包中的upvalue各自独立,调用一次counter()就会产生一个新的闭包
print(counter1()) -- 输出1
print(counter1()) -- 输出2
print(counter2()) -- 输出1

资料参考

【唐老狮】Unity系列之C#四部曲—C#进阶

【唐老狮】Unity热更新之Lua语法

C#闭包

【闭包】

【Unity游戏开发】浅谈Lua和C#中的闭包