Kotlin的高階函數和常用高階函數
高階函數的定義
將函數當做參數或者是返回值的函數
什么是高階函數
可以看看我們常用的 函數:
首先我們可以知道, 是 的擴展函數,然后參數是 ,但是 不再像和我們以前Java那樣傳遞的是一個對象,這時傳遞的是一個函數。這個函數的入參為 ,返回值為 。所以 也是一個高階函數,因為它將函數當做參數進行傳遞了。我們嘗試着去調用一下 函數:
調用的時候,我們將 函數傳遞給了 函數,這里采用的是函數引用。就上訴代碼,我們還可以結合 表達式來進行處理:
其實以上幾種的方式得到的結果都是一樣的,但是第一種就是簡潔了許多。
我們再定義一個類,用來打印 的值:
根據函數引用的特性,我們可以這樣調用 函數:。由於 中的 函數的入參類型是 類型,也就是任意類型,不管 傳遞的是什么值都可以接收。那現在我們再將其作為 的參數傳遞進去:
編譯器告訴我們這個是錯誤的。那我們來分析一下吧:我們再定義一個 類
然后進行以下操作:
可以看到 分別對 和 的解釋:
是一個方法,然后參數類型為 ,返回值為
也是一個方法,但是參數有兩個,分別是 和 類型, 返回值為
在 中,只有一個參數傳遞,但是 需要的是兩個參數,肯定就會報錯,所以我們需要對此進行修改:
這個樣子就OK了。
常用高階函數
map:變換
通常我們會使用以下的方式來實現對集合中的元素進行修改的操作:
如果采用這種方式,遠遠不能體現Kotlin的優勢了,這個和Java有什么區別呢?「狗子,上map」:
從打印結果可以看到他們的實現效果是一模一樣的,這個就是 的功能,可以對集合中的元素進行你想要的操作,是不是跟 的 很類似呢!我們來細看一下 的實現原理:
方法中主要做的就是調用 方法,然后傳遞的是新創建並且初始長度為10的 和 函數,在 方法中,對集合進行迭代,然后將進行變換后的數據添加到新的集合中,最后返回新的集合。
操作不僅可以將元素變換成與之前類型相同的元素,也可以變化成與之前元素類型不同的元素,具體你想變換成什么類型,這個是不做限制的。
flatMap:變換
看起來跟 很相似,其實真的很類似,搞得有時候自己都不知道應該使用哪個操作符了,那就從源碼來看看它們之間的區別吧。
可以看到 中的參數 是一個返回值為 的函數,而 的參數 是一個返回值為 的函數。然后調用 方法,將 和一個新創建的 傳遞給了 方法。在 方法中,對當前的集合進行了迭代,然后將執行過變換操作后的集合數據全部添加到新的集合中,最終返回新的集合。
和 的主要區別就是在於傳入的函數的返回值,一個是任意對象,一個是實現了 接口的對象
reduce
例子:打印集合中的元素之和
還是直接對源碼進行分析吧,感覺看了源碼就一目了然了。
首先對當前的集合進行判空處理,接着將第一個元素賦值給 , 的類型是 。然后對當前集合進行迭代處理,並調用我們傳遞進去的參數 , 函數中傳遞了兩個參數,一個是 類型的,一個是集合元素類型的。 函數的返回值也是 類型的,將 的返回值重新賦值給 。迭代完畢以后返回我們的 。
其實通過我們解讀源碼以后,我們就可以知道 函數會將上一次的計算結果傳遞到下一次計算中,我們可以利用這個方式來實現以下字符串拼接,當然我們的字符串拼接有其他更好的方式,這里只是做為講解 的例子而已:
fold:能夠添加初始值的reduce
不得不說, 跟 的作用基本是一致的,只是 能夠添加初始值,什么叫做能夠添加初始值呢?讓我們來舉個栗子看看唄!
還是看源碼吧:
看着源碼就會覺得這些函數的操作很是簡單了。 函數還有很多的兄弟:
說的再多也不如看結果
這個函數就是多了一個 的參數,具體的用處暫時沒有發現,就不做數據打印了。
filter:過濾
例子:過濾集合中的奇數
上源碼:
在 中創建新的集合 ,將 和 函數一並傳遞給 函數。在 函數中,先對當前的集合進行遍歷,如果滿足條件 就將當前的元素添加到新的集合中, 就是我們傳遞進來的那個函數,返回值是一個 類型的。
takeWhile:截取集合中的數據,直到第一個不滿足條件的元素為止
例子:截取集合中不能夠被5整除的數,直到第一個不滿足條件的元素為止。
源碼:
let:將調用者當做參數傳遞給指定的函數
例子:省略if空判斷
源碼:
源碼也是很簡單,就是將調用者傳遞給傳入進來的函數並執行傳入進來的函數。
apply:執行指定函數,並且返回調用者
例子:修改person類的age屬性
上訴的例子真的只是例子,它沒有跟你講 有多強大,它只是描述了的作用。源碼:
就是單純的執行函數 並返回調用者。
with
例子:文件讀取
源碼:
接收兩個參數,一個是 ,上訴例子中就是 ,另一個就是 ,在上訴例子中,我們使用了 表達式,所以這個函數就移到了括號外面了。
疑惑點
函數定義中 `T.() -> Unit` 和 `() -> Unit` 的區別
我們一般定義函數都會選擇定義
上訴代碼表示: 的擴展方法 接收一個 的函數,該函數是無參無返回的。
那我們再見識見識 這種方式定義的方法,其實也很多見了:
可以看到 函數使用的是 這種方式,他們兩到底有啥區別呢?
我在 定義了兩個方法:
分別使用 調用這兩個方法試試:
從圖片中可以看出 : 中的 對象指的是調用對象 ,也就是 ,而 沒有提示,那么我們就看打印吧:
原來 方法中的 對象指的是外部對象,在這里就是我們的 對象。
總結
這兩個函數唯一的區別就是 與 的區別,我們調用時,在代碼塊里面寫this,的時候,根據代碼提示,我們可以看到,連個this代表的含義不一樣, 里的this代表的是自身實例,而 里,this代表的是外部類的實例
感謝
[Kotlin中,函數作為參數,T.()->Unit 和 ()->Unit 的區別][https://www.jianshu.com/p/88a656e59c61]
This is All