深入理解Perl閉包及其應用
本文和大家重點學習一下Perl閉包的概念,閉包(closure)是個精確但又很難解釋的電腦名詞。在Perl里面,Perl閉包是以匿名函數的形式來實現,具有持續參照位于該函數范圍之外的文字式變數值的能力。
閉包的基本概念
閉包是可以包含自由(未綁定)變量的代碼塊;這些變量不是在這個代碼塊或者任何全局上下文中定義的,而是在定義代碼塊的環境中定義。“閉包”一詞來源于以下兩者的結合:要執行的代碼塊(由于自由變量的存在,相關變量引用沒有釋放)和為自由變量提供綁定的計算環境(作用域)。在Scheme、CommonLisp、Smalltalk、Groovy、JavaScript、Ruby和Python等語言中都能找到對閉包不同程度的支持。
Perl閉包
閉包(closure)是個精確但又很難解釋的電腦名詞。在Perl里面,Perl閉包是以匿名函數的形式來實現,具有持續參照位于該函數范圍之外的文字式變數值的能力。這些外部的文字變數會神奇地保留它們在閉包函數最初定義時的值(深連結)。
如果一個程式語言容許函數遞回另一個函數的話(像Perl就是),Perl閉包便具有意義。要注意的是,有些語言雖提供匿名函數的功能,但卻無法正確處理閉包;Python這個語言便是一例。如果要想多了解閉包的話,建議你去找本功能性程式設計的教科書來看。Scheme這個語言不僅支援閉包,更鼓勵多加使用。
以下是個典型的產生函數的函數:
- subadd_function_generator{
- returnsub{shift+shift};
- }
- $add_sub=add_function_generator();
- $sum=&$add_sub(4,5);#$sum現在是9了
Perl閉包用起來就像是個函數樣板,其中保留了一些可以在稍後再填入的空格。add_function_generator()所遞回的匿名函數在技術上來講并不能算是一個閉包,因為它沒有用到任何位在這個函數范圍之外的文字變數。
把上面這個例子和下面這個make_adder()函數對照一下,下面這個函數所遞回的匿名函數中使用了一個外部的文字變數。這種指名外部函數的作法需要由Perl遞回一個適當的閉包,因此那個文字變數在匿名函數產生之時的值便***地被鎖進閉包里。
- submake_adder{
- my$addpiece=shift;
- returnsub{shift+$addpiece};
- }
- $f1=make_adder(20);
- $f2=make_adder(555);
這樣一來&$f1($n)永遠會是20加上你傳進去的值$n,而&$f2($n)將永遠會是555加上你傳進去的值$n。$addpiece的值會在閉包中保留下來。
Perl閉包在比較實際的場合中也常用得到,譬如當你想把一些程式碼傳入一個函數時:
my$line;
timeout(30,sub{$line=<STDIN>});
如果要執行的程式碼當初是以字串的形式傳入的話,即'$line=<STDIN>',那么timeout()這個假想的函數在回到該函數被呼叫時所在的范圍後便無法再擷取$list這個文字變數的值了。
【編輯推薦】