天天看點

本人了解的閉包的概念

對于閉包的概念,起先是函數式程式設計的語言才有的,如LISP,Haskell等。通常是支援函數式程式設計的語言才有的特性。目前很多指令式語言諸如javascript,C#等也能實作函數式程式設計,也有了閉包的概念。

閉包的定義比較抽象晦澀,本人了解的閉包的概念其實就是在函數中定義一個子函數,通過該子函數可以讀取父函數中的值。下面以F#為例。F#是微軟發展的基于.NET的一個函數式語言。

假設有一個函數,求一個數平方和。

  1. //計算平方和
  2. let calculate  x y=
  3.     let square1=x*x
  4.     let square2=y*y
  5.     let squaresum()=
  6.         square1+square2
  7.     squaresum()
  8. printfn "%i" (calculate 3 4)

結果如下:

本人了解的閉包的概念

此處  squaresum 函數就是一個閉包函數,它可以讀取square1和square2的值。

事實上,該函數可以柯裡化,柯裡化後就隻有1個參數,傳回的一個squaresum函數。

  1. let calculate x=
  2.     let squaresum=fun y->square1+y*y
  3.     squaresum
本人了解的閉包的概念

此squaresum函數實際上也是閉包函數,它能讀取square1的值。注意此 calculate 函數的調用方式,他先用參數3運算,傳回的是一個函數squaresum,然後由squaresum再次調用參數4,計算出是25。是以,可以看出,在第二次調用的時候,不經意的已經使用了square1參數。如果還不夠了解,可以看下面的寫法,拆開來寫。

  1.     let square1=x*x;
  2.     printfn "call calculate->square1:%i" square1;
  3.     let squaresum=fun y->(printfn "call squaresum->square1:%i" square1;square1+y*y)
  4. let tmp_squaresum=calculate 3;
  5. printfn "%i" (tmp_squaresum 4)
本人了解的閉包的概念

由代碼運作結果看到,先調用calculate,此函數算出square1的值為9,列印出。然後把squaresum作為傳回值後,指派給tmp_squaresum,然後退出了。接着,調用tmp_squaresum了。神奇的發現square1的值還是9。這就是閉包的作用。雖然主函數運作結束了,但是由于它的子函數需要用到主函數中的值,是以該函數仍然持有在記憶體中,并不馬上退出。

程式員不需要做什麼特殊的工作來保持這個局部變量,.NET的編譯器會自動的處理閉包,将父函數中的局部變量仍然持有着,直到垃圾回收機制來回收。由于局部變量不會被釋放,是以過度的使用閉包,導緻記憶體緊張,是以沒有必要的情況下,盡量不使用閉包。

繼續閱讀