<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          淺析函數(shù)式編程

          共 5962字,需瀏覽 12分鐘

           ·

          2023-05-18 05:33

          函數(shù)式編程

          1. 函數(shù)

          高中一年級,應(yīng)該是最早接觸函數(shù)這個概念的時間,印象很深刻,畢竟是高考壓軸大題,但它卻是必修一第二章的內(nèi)容。

          我們來看一個必修一中最簡單的一個函數(shù):

          上面的函數(shù)由三個部分組成:

          • x 自變量,由它決定初始值
          • f 它代表一個規(guī)則,用來對 自變量 進行計算。它也是用來描述函數(shù)關(guān)系的。
          • y 因變量,它用來標(biāo)識通過函數(shù)計算以后的結(jié)果

          一個函數(shù)的定義是:「一個自變量 x ,經(jīng)過一個規(guī)則 f(x) 的運算,得到一個因變量。其中的規(guī)則 f(x) 稱為函數(shù)」

          上面的函數(shù)在數(shù)學(xué)上有一個術(shù)語叫「一元函數(shù)」

          如上,它被稱為「二元函數(shù)」,自變量的多少決定了這個函數(shù)的名稱。

          函數(shù)的概念,也被引入了計算機的領(lǐng)域中。很多的語言內(nèi)置了函數(shù)的語法,幫助我們?nèi)崿F(xiàn)類似于數(shù)學(xué)中函數(shù)的功能。

          我們來看一個函數(shù)的定義

                
                int?main(int?x)?{
          ?return?x?+?1;?
          }

          這是 C 語言中定義一個函數(shù)的語法規(guī)則,可以看出它和數(shù)學(xué)中的函數(shù)完全一樣,它傳入了一個自變量 x 在計算機中,它叫「參數(shù)」,同時在函數(shù)內(nèi)部,它對這個參數(shù)做了加法運算,并將其返回。此時這個加法運算就是數(shù)學(xué)中的規(guī)則 f(x) ,返回值就是因變量 y

          類似,上面的函數(shù)叫一元函數(shù),因為他只有一個參數(shù)。

          同理,兩個參數(shù)的,就稱為二元函數(shù),以此類推。

          各種編程語言,提供了多種多樣的函數(shù)的定義方式,但其本質(zhì)和上面的函數(shù)完全一樣,只是定義方式發(fā)生了變化而已。

          • Java
                
                public?static?int?method(int?x)?{
          ??return?x?+?1;
          }
          • scala
                
                def?method(x:?Int):?Int?=?{
          ??x?+?1
          }
          • javascript
                
                function?method(x)?{
          ??return?x?+?1
          }

          2. 面向?qū)ο缶幊毯秃瘮?shù)式編程

          寫 OOP 的人都有一個體會,以類作為最小的調(diào)度單元,實現(xiàn)一個功能,需要去「定義一些數(shù)據(jù)結(jié)構(gòu)和操作這些數(shù)據(jù)結(jié)構(gòu)的方法」。

          也基于此,衍生出了設(shè)計模式這個代碼復(fù)用的規(guī)則。設(shè)計模式的出現(xiàn)就是為了解決 OOP 帶來的一些弊端,一定程度上實現(xiàn)對方法級別的重用。

          函數(shù)式編程(后文以 FP 代替)講究不變性,如同一個數(shù)學(xué)函數(shù)一樣,只要你的入?yún)⑾嗤?,那么你的返回值必然相同,這樣做的好處在于,「這個函數(shù)對你的代碼沒有任何副作用,它不會更改所有的變量,只會返回一個新的變量,這也意味著它沒有線程安全的問題?!?/strong>

          了解過一些支持 FP 的同學(xué),一定在相關(guān)的書籍上看到過一句話:「函數(shù)是一等公民」,支持 FP 的語言,將函數(shù)作為一種數(shù)據(jù)類型而存在。

          而當(dāng)函數(shù)成為一種數(shù)據(jù)類型的時候,很多我們經(jīng)常使用到的設(shè)計模式也就有了其他的一些玩法。

          3. 函數(shù)式編程下的設(shè)計模式

          策略

          策略設(shè)計模式,用來解決參數(shù)相同場景下的 if|else 的問題,直接看類圖3af114404afeb98cadb235f49f953d7d.webp

          • Strategy(策略),定義所有支持的算法的公共接口。
          • ConcreteStrategy(具體策略,如 SimpleCompository , TeXCompositor)
          • Context (上下文,用來對具體的策略進行切換)

          上面是典型的 OOP 的思路,我們來看一下 FP 下的代碼實現(xiàn)

                
                function?test01(func)?{
          ??func("HelloWorld")
          }

          function?test02(str)?{
          ??log.info(str)
          }

          test01(test02())

          模版方法

          模版方法,預(yù)留一些擴展(方法)留給子類自己實現(xiàn),如生命周期函數(shù)。來看類圖

          e38c82f628a823c53c70ee8fadeb9784.webp

          FP函數(shù)式代碼實現(xiàn):

                
                function?test01(doCreateDocument,?aboutToOpenDocument)?{
          ??log.info("start")
          ??doCreateDoCument(str)
          ??aboutToOpenDocument(str)
          }

          test01(data?=>?{
          ??
          },?error?=>?{
          ??
          })

          可以發(fā)現(xiàn)無論是策略還是模版設(shè)計模式,都在使用函數(shù)作為數(shù)據(jù)類型,進而代替了 OOP 中的繼承的作用。但對于一個函數(shù)而言,參數(shù)的個數(shù)問題成為了一個問題,實現(xiàn)一個功能我們可以依賴于外部的多個參數(shù),此時一味的進行傳參,對于后續(xù)代碼維護、擴展都有很大的影響,于此函數(shù)式編程的一個特性也隨之誕生。

          4. 柯里化

          閉包

          閉包的概念來自于前端,通俗的話來講,「閉包就是引用了一個函數(shù)內(nèi)部所有變量(包括參數(shù))的一個組合?!?/strong>

          閉包在函數(shù)創(chuàng)建的時候就會被默認創(chuàng)建,如同類的構(gòu)造函數(shù)。

          ?

          一個問題:沒有返回值的函數(shù)存在閉包嗎?

          答:存在,沒有使用而已

          ?

          上面提到了一個多參數(shù)的問題,我們來看一段代碼

                
                function?func1(str1)?{
          ??return?func2(str2)?{
          ????return?str1?===?str2
          ??}
          }

          const?func3?=?func1("1")
          const?ans?=?func3("2")

          可以看到,func1 返回了一個函數(shù) func2 ,func2 函數(shù)訪問了 func1 函數(shù)的參數(shù)。這個的實現(xiàn)就依賴于 「閉包」。

          func3 獲取到了 func2 的一個引用。此時繼續(xù)調(diào)用 func3 ,得到 func1 最終的處理結(jié)果。

          上面將函數(shù)調(diào)用分為了兩步,如果連在一起寫就是 func1("1")("2")。

          ?

          Func1(1)(2) 這樣寫的好處在哪里?

          ?
          • 將一個多元函數(shù)拆分為多個低元函數(shù),參數(shù)之間可以進行預(yù)處理,然后進行整合;

          • 一元函數(shù)方便復(fù)用

          這種變形調(diào)用方式,在函數(shù)式編程中存在一個術(shù)語「柯里化」。

          5. Java 中的函數(shù)式

          從 1.8 開始 Jdk 從語言層面提供了一些能力用以在 Java 領(lǐng)域書寫一些函數(shù)式編程。

          函數(shù)作為參數(shù)

          Java 1.8 以后提供了一個注解 @FunctionalInterface 。它的定義是:內(nèi)部僅僅存在一個抽象方法的接口,即可聲明為函數(shù)式接口。同時也提供了一些通用的類,來實現(xiàn)函數(shù)式編程。

          c3708578cb1b82a43dc40980ca0435c9.webp

          圖中最上面是四個基本的函數(shù)式接口,Consumer, Predicate, Supplier 三個類都是對 Function 類的一次封裝,Consumer 類沒有返回值,Predicate 返回值為 「布爾值」Supplier 類沒有參數(shù)。而 Function 類是一個標(biāo)準(zhǔn)的函數(shù)式接口,看一下它的定義。

                
                @FunctionalInterface
          public?interface?Function<T,?R>?{

          ????/**
          ?????*?Applies?this?function?to?the?given?argument.
          ?????*
          ?????*?@param?t?the?function?argument
          ?????*?@return?the?function?result
          ?????*/

          ????R?apply(T?t);
          ??
          ???default?<V>?Function<V,?R>?compose(Function<??super?V,???extends?T>?before)?{
          ????????Objects.requireNonNull(before);
          ????????return?(V?v)?->?apply(before.apply(v));
          ????}
          ???default?<V>?Function<T,?V>?andThen(Function<??super?R,???extends?V>?after)?{
          ????????Objects.requireNonNull(after);
          ????????return?(T?t)?->?after.apply(apply(t));
          ????}
          ??
          }

          可以看到,他內(nèi)部提供了一個抽象函數(shù), R apply(T t) 接受一個泛型,返回一個泛型。「這是最標(biāo)準(zhǔn)的一元函數(shù)(只有一個參數(shù))?!?/strong>

          那么問題來了,如果我需要兩個參數(shù)怎么辦,JDK,提供了一個 BiFunction 可以接受兩個參數(shù),當(dāng)然只能返回一個值,如果想返回多個值,請封裝一個 集合類型。

          那么問題又來了,如果我需要三個,或者更多的參數(shù)怎么辦,不可能 JDK 將所有的參數(shù)個數(shù)的函數(shù)都封裝一遍吧。

          我們來思考一下這個問題的解決方法:對于多元(多參)的函數(shù),我們能否將它們拆成一個個的一元函數(shù),然后讓這個一元函數(shù)返回一個一元函數(shù),來實現(xiàn)多參數(shù)的傳遞。這就是我們前面提到的柯里化的思想。

          來看一下具體的實現(xiàn)

                
                public?void?test()?{
          ????????System.out.println(test01(param01?->?param02?->?param03?->?param01?+?param02?+?param03));
          ????}

          ????public?String?test01(Function<String,?Function<String,?Function<String,?String>>>?function)?{
          ????????//?condition

          ????????String?method01?=?"111";
          ????????String?method02?=?"222";
          ????????String?method03?=?"333";

          ????????return?function.apply(method01).apply(method02).apply(method03);
          ????}

          通過以上的方式可以簡單的去寫一些服用代碼,比如返回值相同但是調(diào)用方方不同的第三方調(diào)用。

          以上就是對函數(shù)式編程的一個簡單的介紹,具體的其他行為需要在真正的編碼中進行實踐。

          創(chuàng)

          l s p 內(nèi)

          態(tài) 設(shè)

          設(shè)

          設(shè)

          T h r e a d L o c a l ?




          瀏覽 31
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    豆花视频在线欧美亚洲自拍 | 3G毛片 | 亚洲成人A片 | 欧美一级aⅴ毛片 | 北条麻妃无码一区二区 |