C 溫故而知新系列 閉包

2021-08-18 03:29:47 字數 2619 閱讀 8450

要說閉包的由來就不得不先說下函式式程式設計了。近幾年函式式程式設計也是比較火熱,我們先來看看函式式程式設計的一些基本的特性這個有助於我們理解閉包的由來。

函式式程式設計是一種程式設計模型,他將計算機運算看做是數學中函式的計算,並且避免了狀態以及變數的概念。這裡很明顯的指出了函式式程式設計中最重要的就是函式而且是數學中的函式,比如f(x),數學中的函式最大的特點就是只要是同樣的引數x那麼我的結果必定是相等的,也就是說我們函式的返回值只是依賴於引數而不依賴於其他狀態(比如js中的全域性變數就是乙個干擾因素);後一句中說避免變數的概念,這句話如果從函式式程式設計來說不太恰當,因為這句話中的函式意思還是我們在程式語言中所使用的變數也就是乙個儲存單元,而在函式式程式設計中變數卻是數學中變數的定義是乙個值得名稱。比如,我們最基本的賦值等式 x = x+1,讓我們程式設計師看這是乙個簡單的賦值**,而讓學數學的人來說這個等式是根本不成立的。 所以我們在函式式程式設計中是不允許多次賦值的。而這一句話也是講述了函式式程式設計好處的最主要的原因:

第一點、函式的結果只依賴於引數而不依賴其他狀態,這樣寫的**很容易進行推理不容易發生錯誤,極大的方便的單元測試和除錯。

第二點、因為不可變性和無狀態,那麼我們在處理多個執行緒之間就不用擔心資源的爭奪,不需要用鎖來儲存狀態。

高階函式

函式式程式設計中函式是一等公民,和我們的口號 "萬物皆物件"有點相似,在函式式程式設計中,我們努力用函式來表達所有的事情,當然我們也需要函式可以傳過來傳過去這就是高階函式,也就是把函式作為引數或者返回值,繼而實現復用,這樣即是可以把復用的粒度降到函式。c#語言中也有類似的東西--委託,當然c#中的函式跟函式式程式設計中的就不一樣了,但是有吸收一些函式式程式語言中的特性,比如c#中lamda,linq。

關於函式式程式設計有很多很好的文章介紹我就不詳說了,接下來就是引出我們今天的主題--閉包。

因為函式式程式設計的基礎就是lambda演算,所以這一節演算我們用lambda演算來帶出我們的主題,關於這個演算我也懂得不是太多,想要入門的同學可以看看這個  點這裡

首先定義乙個簡單的演算

λx.λy.x+y

如果x為1 y為2 演算過程則為

((λx.λy.x+y)1)2=(λy.1+y)2=(1+2)=3

接下來我們用到高階函式 

λy . (λx . x + y)

演算過程:

((λy . (λx . x + y))1)2=((λx . x + 1))2 = (2+1)=3

可以看到這個演算中外層函式使用的是內層函式,也就是說使用是乙個函式作為了計算結果。ok ,我們把內層函式單獨拿出來,(λx . x + y),可以很明顯的看到如果脫離的上下文呢,我們的y是沒有值的,也就是y是沒有繫結的,也可以說y對於我們這個函式是自由的! 如果在函式式程式設計中,在外層函式執行完畢之後我們的y變數就應該被銷毀,那麼如果我們在內層函式中如果還需要用到y的話怎麼辦呢? 對於這個問題,設計者則做了其他的處理:如果乙個函式返回另乙個函式,而被返回函式又需要外層函式的變數時,不會立即釋放這個變數,而是允許被返回的函式引用這些變數。支援這種機制的語言稱為支援閉包機制,而這個內部函式連同其自由變數就形成了乙個閉包(這句話是摘自其他部落格,自己難得整理文字。。。)。這就是我們閉包的由來,而我們其他的語言如果有用到函式式程式設計的思想,並且允許函式來進行傳遞就會遇到類似的問題,所以各個語言就需要用其自己的方式來實現閉包!

從上一節我們也就是能總結出閉包其實就是要執行並且包含自由變數的**塊(由於自由變數被包含在**塊中,這些自由變數以及它們引用的物件沒有被釋放)和為自由變數提供繫結的計算環境的乙個結合。 

然後進入我們的c#程式設計時刻了,我們就用簡單的例子來實現,並且檢視編譯器生成的** 看看c#中是怎麼實現閉包,畢竟我們也是有委託的 。。。

首先寫乙個簡單得不能在簡單的**

1

using

system;23

namespace

closure413

14public

static func test(int

x)15;22

}23}24 }

可以看到我們test的方法中傳入變數x的作用域是在1 在執行匿名函式的時候應該是已經釋放在作用域2就不應該存在了,而我們卻能準確的得到計算結果    

說明我們的變數x確實在作用域2中還存在,接下來我們看看編譯器幫我們做了什麼事情,

可以看到我們的test方法中多了乙個物件 <>c__displayclass1_0  class_;這個東西的具體定義是啥?

這個很明顯了,其實閉包只是編譯器幫我們把自由變數封裝到了乙個物件中供我們作用域外使用,那我們如果去掉作用域2中使用x變數呢?

編譯器原來為了自由變數維護的物件沒了 。。。結果在意料之中。

ok,這篇文章就到此結束了,關於閉包是python中啊 js中啊 或者c#中得用處我就不細說了,中有太多太多的介紹了,希望這邊文章對你有幫助,歡迎拍磚!

C 溫故而知新系列 閉包

要說閉包的由來就不得不先說下函式式程式設計了。近幾年函式式程式設計也是比較火熱,我們先來看看函式式程式設計的一些基本的特性這個有助於我們理解閉包的由來。函式式程式設計是一種程式設計模型,他將計算機運算看做是數學中函式的計算,並且避免了狀態以及變數的概念。這裡很明顯的指出了函式式程式設計中最重要的就是...

溫故而知新(構造 閉包 this)

建構函式 老生常談的東西,一句帶過,建構函式就是與類名相同,用來在編譯時對類的變數進行記憶體分配和初始化。閉包 js的閉包概念,閉包就是能夠讀取其他函式內部變數的函式。在本質上,閉包就是將函式內部和函式外部連線起來的一座橋梁。當函式a的內部函式b被函式a外的乙個變數引用的時候,就建立了乙個閉包。它的...

溫故而知新

堆排 建立堆,維護堆的屬性 一次拿掉乙個,然後維護屬性,二分的結構 使得維護屬性只要logn的時間 冒泡也是一次拿走乙個 但是線性的結構 每次沒有節省時間 快排 一次確定 乙個值的位置,然後二分,縮小問題的範圍。floyd找最短 一次更新 將狀態改為經過固定點的 最短距離 迴圈 遍歷每個點,則結果為...