翻車(chē)了!T稀屠尊!一個(gè)小例子帶你了解閉包。
事故現(xiàn)場(chǎng):
場(chǎng)景:6個(gè)button耕拷,上方1個(gè)text讼昆。點(diǎn)擊button,text會(huì)顯示button上的數(shù)字骚烧。
代碼如下:
//在unity里面賦值
public List<Button> buttons = new List<Button>();
public Text text;
void Start () {
AddFun();
}
//給6個(gè)button添加點(diǎn)擊事件
void AddFun()
{
for (int i = 0; i < buttons.Count; i++)
{
buttons[i].onClick.AddListener(() => Fun(i + 1));
}
}
//點(diǎn)擊事件:輸出形參的值
void Fun(int i)
{
text.text = i.ToString();
print(i);
}
for循環(huán)button添加onclick函數(shù)導(dǎo)致點(diǎn)擊所有的button顯示同樣的莫名數(shù)字7浸赫。
事故原因:
閉包。標(biāo)題那么長(zhǎng)跟閉包有什么關(guān)系止潘?因?yàn)樯鲜鰡?wèn)題會(huì)引起閉包掺炭。為什么標(biāo)題中不直接寫(xiě)出關(guān)鍵字閉包辫诅?因?yàn)榻械某鲩]包的人基本上都會(huì)避免這個(gè)問(wèn)題凭戴,這篇文章主要針對(duì)新人,那些沒(méi)聽(tīng)過(guò)閉包的人炕矮。
事故分析:
1么夫、什么是閉包?我也不知道哈肤视,非科班档痪,定義百度一下吧。
2邢滑、怎么會(huì)產(chǎn)生閉包腐螟??jī)?nèi)部函數(shù)使用了外部函數(shù)的局部變量。內(nèi)部函數(shù):是我對(duì)匿名函數(shù)困后,lambda表達(dá)式等函數(shù)嵌套情況的稱(chēng)呼乐纸。如上述例子:外部函數(shù)Addfun,內(nèi)部函數(shù)是lambda表達(dá)式摇予,i是外部函數(shù)for循環(huán)中的局部變量汽绢,內(nèi)部函數(shù)lambda表達(dá)式使用了i這個(gè)局部變量。
3侧戴、閉包會(huì)導(dǎo)致什么的結(jié)果宁昭?閉包會(huì)延長(zhǎng)所用外部函數(shù)局部變量的生命周期,或者說(shuō)是局部變量變成了全局變量酗宋。
內(nèi)存分析:
通俗的講就是局部變量i從沒(méi)被釋放积仗,一直存在內(nèi)存中,隨著i++蜕猫,值增到了6斥扛,所有button的點(diǎn)擊函數(shù)都是傳進(jìn)的i+1,也就是7,為實(shí)參稀颁,所以fun函數(shù)打印的數(shù)字為7
處理辦法:
重新申請(qǐng)內(nèi)存芬失。代碼如下:
public List<Button> buttons = new List<Button>();
public Text text;
void Start () {
AddFun();
}
void AddFun()
{
for (int i = 0; i < buttons.Count; i++)
{
//重新申請(qǐng)的內(nèi)存
int index = i;
buttons[i].onClick.AddListener(() => Fun(index + 1));
}
}
void Fun(int i)
{
text.text = i.ToString();
print(i);
}
內(nèi)存分析:
通過(guò)初始化重新申請(qǐng)了6塊內(nèi)存,每塊內(nèi)存保存了不同的index值(index值是由i賦值而來(lái))匾灶。雖然index變量的生命周期也被延長(zhǎng)棱烂,但是不同的button的點(diǎn)擊函數(shù)訪(fǎng)問(wèn)的傳進(jìn)參數(shù)的內(nèi)存不同,因此fun函數(shù)打印的數(shù)字也就不同阶女。
事件解決:
拓展:
其實(shí)閉包在腳本語(yǔ)言中非常常見(jiàn)颊糜,也非常有用。以lua為例秃踩,代碼如下:
function OutSideFun()
local i=0
local function InsideFun()
i=i+1
print(i)
end
return InsideFun
end
local fun=OutSideFun()
fun()
fun()
fun()
那么自己可以試試輸出值是多少衬鱼,分析一下為什么是這樣。
小結(jié)
知識(shí)點(diǎn):閉包憔杨,會(huì)導(dǎo)致外部函數(shù)的局部變量生命周期延長(zhǎng)鸟赫。