徹底說清楚scala中的閉包和柯里化的概念

堅持說大白話,讓問題儘可能的簡單易懂!

 

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要進行閉包的清理 。。。。 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章