堅持說大白話,讓問題儘可能的簡單易懂!
1:前言:
閉包和柯里化是學習scala的過程中以及面試的過程中無法忽視的一道坎,不管你是否重視它,它都存在。筆者之前也是對這些東西雲裏霧裏,因爲Java裏本身沒有閉包這個概念的,接觸過JS的同學可能知道閉包的概念,我沒有接觸過JS裏的閉包所以也不敢去做對比,這裏就我的一些理解和體會分享給大家。
2:閉包:
文檔裏的英文是 closure 是關閉的意思,翻譯過來是閉包。到底怎麼算是關閉了呢?關進去的又是什麼呢?
把誰給關進去了?
把函數外部的一個自由變量給關進去了。
val a = 3
def f(x:Int)={
x + a
}
這裏的 a 是個自由便量,這裏的f是個函數。可以看到 如果說我們調用函數 f (2) 的話 ,那麼我們知道這個計算的結果是依賴於這個自由變量 a 的 ,有人說閉包是改變了作用域,筆者認爲欠妥,何爲改變作用域?不清楚。
閉包最根本的是什麼?
閉包最根本的是改變了 a 的生命週期,這個是最關鍵的,最本質的。
def f1(x:Int)={
def f2(y:Int)={
x+y
}
f2 _
}
在Scala裏函數是頭等公民,這種嵌套的方式是沒問題的。並且函數可以作爲返回值。
當我們調用函數 f1(3) 的時候,按道理說,當我們 f(1) 被調用完畢之後按道理來說作爲局部變量的 x 因該隨之彈棧纔對,這裏是最關鍵的地方,但是,x 能彈棧嗎?如果彈棧那麼這個變量就無法被使用了,但是 但是 f2() 此時引用着它,f2() 還沒運行 你說 f2() 能讓它彈棧嗎?很顯然是不會。這個時候 x就被捕獲了,其實就是把它關起來了,所以閉包最本質的就是改變了 外部變量的生命週期。
3:柯里化
柯里化我剛接觸的時候感覺很不可思議。這種語法格式在java裏是不敢想的,但是用起來就覺得這個東西其實還是挺方便的。柯里化其實不是什麼高深的東西,下面讓筆者來拆解一下:
def f1(x:Int)={
def f2(y:Int)={
x+y
}
f2 _
}
用的還是上面的那個例子
我們來拆解一下:
我們調用函數 f1(2) 得到的結果是:
val func: Int => Int = f1(2)
func: Int => Int = <function1>
可以清楚的看到 返回的是一個函數。不得不說在scala裏對於函數真的很靈活。
那麼我們調用 f1(2) 返回的就是 函數 f2 ,我們調用一下f2 這個函數那麼就是 : f1(2)(3) 這裏是重點,看出來門道了沒?這不就是柯里化的表達方式嗎?其實到這裏柯里化的遮羞布已經被扯下來了。
其實就是函數的嵌套調用。
我爲什麼拿同樣的一個例子來說明閉包和柯里化呢?
因爲他們其實有關聯,怎麼關聯呢?
其實柯里化是離不開閉包的,因爲函數的嵌套調用本身就是閉包,你想是不是??? f2 用到了外部的f1 裏的變量,這不是閉包嗎?
今天就先說到這裏吧。下次再聊一下,scala裏的閉包怎麼就導致了spark要進行閉包的清理 。。。。