函數編程之閉包漫談(Closure)

在學習golang和scala語言時,對閉包這個概念理解的一直不是很好,直到今天看到一篇博文,感受茅塞頓開。下面是全文的轉載:程序員

原文地址:http://www.cnblogs.com/Jifangliang/archive/2008/08/05/1260602.htmgolang

在函數編程中常常用到閉包。閉包是什麼,它是怎麼產生的及用來解決什麼問題呢。給出字面的定義先:閉包是由函數及其相關的引用環境組合而成的實體(即:閉包=函數+引用環境)。這個從字面上很難理解,特別對於一直使用命令式語言進行編程的程序員們。本文將結合實例代碼進行解釋。
函數是什麼
地球人都知道:函數只是一段可執行代碼,編譯後就「固化」了,每一個函數在內存中只有一份實例,獲得函數的入口點即可以執行函數了。在函數式編程語言中,函數是一等公民(First class value:第一類對象,咱們不須要像命令式語言中那樣藉助函數指針,委託操做函數),函數能夠做爲另外一個函數的參數或返回值,能夠賦給一個變量。函數能夠嵌套定義,即在一個函數內部能夠定義另外一個函數,有了嵌套函數這種結構,便會產生閉包問題。如:
編程

複製代碼
>>>   def  ExFunc(n):
     sum
= n
     
def  InsFunc():
             
return  sum + 1
     
return  InsFunc

>>>  myFunc = ExFunc( 10 )
>>>  myFunc()
11
>>>  myAnotherFunc = ExFunc( 20 )
>>>  myAnotherFunc()
21
>>>  myFunc()
11
>>>  myAnotherFunc()
21
>>>
複製代碼

在這段程序中,函數InsFunc是函數ExFunc的內嵌函數,而且是ExFunc函數的返回值。咱們注意到一個問題:內嵌函數InsFunc中引用到外層函數中的局部變量sum,IronPython會這麼處理這個問題呢?先讓咱們來看看這段代碼的運行結果。當咱們調用分別由不一樣的參數調用ExFunc函數獲得的函數時(myFunc(),myAnotherFunc()),獲得的結果是隔離的,也就是說每次調用ExFunc函數後都將生成並保存一個新的局部變量sum。其實這裏ExFunc函數返回的就是閉包。
數組

引用環境
按照命令式語言的規則,ExFunc函數只是返回了內嵌函數InsFunc的地址,在執行InsFunc函數時將會因爲在其做用域內找不到sum變量而出錯。而在函數式語言中,當內嵌函數體內引用到體外的變量時,將會把定義時涉及到的引用環境和函數體打包成一個總體(閉包)返回。如今給出引用環境的定義就容易理解了:引用環境是指在程序執行中的某個點全部處於活躍狀態的約束(一個變量的名字和其所表明的對象之間的聯繫)所組成的集合。閉包的使用和正常的函數調用沒有區別。閉包

因爲閉包把函數和運行時的引用環境打包成爲一個新的總體,因此就解決了函數編程中的嵌套所引起的問題。如上述代碼段中,當每次調用ExFunc函數時都將返回一個新的閉包實例,這些實例之間是隔離的,分別包含調用時不一樣的引用環境現場。不一樣於函數,閉包在運行時能夠有多個實例,不一樣的引用環境和相同的函數組合能夠產生不一樣的實例。編程語言

相關文章
相關標籤/搜索