闭包问题汇总(之前有个大佬时不时问几个问题,现在来总结下经验)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ToggleTest : MonoBehaviour
{
public Toggle[] toggles;
private void Start() {
for (int i = 0; i < toggles.Length; i++)
{
toggles[i].onValueChanged.AddListener((isOn)=>OnToggleChanged(isOn,i));
}
}
private void OnToggleChanged(bool isOn,int index){
Debug.Log($"index==>{
index}..State===>{
isOn}");
}
}
看到这里可以先猜猜选择Toggle打印结果会是多少?Toggle单选按钮有三个。
可以看到Index始终为3。。。
为什么结果会是3呢?这里就会提到闭包这个概念:内层的函数可以引用包含在它外层的函数的变量,即使外层函数的执行已经终止。但该变量提供的值并非变量创建时的值,而是在父函数范围内的最终值。正常来讲For循环执行完毕的时候i变量的内存会随着For循环结束而结束生命。但是由于匿名函数引用了i,导致i不能随For循环结束而结束。所以这个时候i=3.当我们执行点击的时候index=3.这里问题就找到了,那么应该如何解决呢?
解决方案
这样就解决了。想要弄清楚解决的思路,还是得从内存谈起。上一张没有int t = i的代码中。i有几个内存地址呢?可以看出来i只有一个内存地址。而当前图中t有几个内存地址呢?很明显有三个,每次For循环进来都会声明一个t的内存地址。并且t的值随着For循环结束都是不同的。分别是0,1,2。所以问题到这里就可以完全理解了。
Lua中的闭包
function newCounter()
local i = 0
return function()
i = i + 1
return i
end
end
c1 = newCounter()
print(c1())
print(c1())
结果应该是1,2.i本来应该在NewCounter调用结束时候就随之释放内存。但是由于内部函数引用,所以内存继续存在,第一次执行完c1()i = 0+1 = 1;第二次执行c1()完i就应该为i = 1+1 =2;
function newCounter()
local i = 0
return function()
i = i + 1
return i
end
end
c1 = newCounter()
print(c1())
c1 = nil
c2 = newCounter()
print(c2())