日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
一篇帶給你Kotin高階函數(shù)詳解

 前言

在Kotlin中,高階函數(shù)是指將一個(gè)函數(shù)作為另一個(gè)函數(shù)的參數(shù)或者返回值。如果用f(x)、g(x)用來(lái)表示兩個(gè)函數(shù),那么高階函數(shù)可以表示為f(g(x))。Kotlin為開發(fā)者提供了豐富的高階函數(shù),比如Standard.kt中的let、with、apply等,_Collectioins.kt中的forEach等。為了能夠自如的使用這些高階函數(shù),我們有必要去了解這些高階函數(shù)的使用方法

創(chuàng)新互聯(lián)公司是一家網(wǎng)站設(shè)計(jì)公司,集創(chuàng)意、互聯(lián)網(wǎng)應(yīng)用、軟件技術(shù)為一體的創(chuàng)意網(wǎng)站建設(shè)服務(wù)商,主營(yíng)產(chǎn)品:成都響應(yīng)式網(wǎng)站建設(shè)品牌網(wǎng)站制作、成都全網(wǎng)營(yíng)銷推廣。我們專注企業(yè)品牌在網(wǎng)站中的整體樹立,網(wǎng)絡(luò)互動(dòng)的體驗(yàn),以及在手機(jī)等移動(dòng)端的優(yōu)質(zhì)呈現(xiàn)。成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作、移動(dòng)互聯(lián)產(chǎn)品、網(wǎng)絡(luò)運(yùn)營(yíng)、VI設(shè)計(jì)、云產(chǎn)品.運(yùn)維為核心業(yè)務(wù)。為用戶提供一站式解決方案,我們深知市場(chǎng)的競(jìng)爭(zhēng)激烈,認(rèn)真對(duì)待每位客戶,為客戶提供賞析悅目的作品,網(wǎng)站的價(jià)值服務(wù)。

今天我們來(lái)講解高階函數(shù)

一、高階函數(shù)詳解

1、高階函數(shù)是什么?

  • 如果一個(gè)函數(shù)接收另一個(gè)函數(shù)作為參數(shù),或者返回值的類型是另一個(gè)函數(shù),那么該函數(shù)就稱為高階函數(shù)。
  • 與java不同的是,在Kotlin中增加了一個(gè)函數(shù)類型的概念,如果我們將這種函數(shù)添加到一個(gè)函數(shù)的參數(shù)聲明或返回值聲明當(dāng)中,那么這就是一個(gè)高階函數(shù)了。
  • 函數(shù)類型語(yǔ)法基本規(guī)則:(String,Int) -> Unit添加到某個(gè)函數(shù)的參數(shù)聲明
 
 
 
 
  1. public fun test2(test:Int,block:()->Unit){ 
  2.  
  3. var v= block() 
  4.  
  5. DTLog.i("TestTest","Test1") 
  6.  
  7.  
  8. public fun T.test22(block:()->T):T{ 
  9.  
  10. return block() 
  11.  
  12.  
  13. public fun T.test26(block:T.()->Unit){ 
  14.  
  15. block() 
  16.  
  17.  
  18. public fun T.test23(block:(T)->Unit):T{ 
  19.  
  20. return this 
  21.  
  22.  
  23. public fun 
  24.  
  25. var t=block(this) 
  26.  
  27. return t 
  28.  
  29.  
  30. public fun 
  31.  
  32. return block(this) 
  33.  

以上就是一個(gè)高階函數(shù),它接收了一個(gè)函數(shù)類型的參數(shù),而調(diào)用高階函數(shù)的方法與調(diào)用普通函數(shù)差異不大,只需要在參數(shù)名后面加上括號(hào),并在括號(hào)中傳入必要的參數(shù)即可;

高階函數(shù)類型具有與函數(shù)簽名相對(duì)應(yīng)的特殊表示法,即它們的參數(shù)和返回值:

  • 所有函數(shù)類型都有一個(gè)圓括號(hào)括起來(lái)的參數(shù)類型列表以及一個(gè)返回類型:(A, B) -> C 表示接受類型分別為 A 與 B 兩個(gè)參數(shù)并返回一個(gè) C類型值的函數(shù)類型。參數(shù)類型列表可以為空,如 () -> A ,返回值為空,如(A, B) -> Unit;
  • 函數(shù)類型可以有一個(gè)額外的接收者類型,它在表示法中的點(diǎn)之前指定,如類型 A.(B) -> C 表示可以在 A 的接收者對(duì)象上,調(diào)用一個(gè)以 B 類型作為參數(shù),并返回一個(gè) C 類型值的函數(shù)。
  • 還有一種比較特殊的函數(shù)類型,掛起函數(shù),它的表示法中有一個(gè) suspend 修飾符 ,例如 suspend () -> Unit 或者 suspend A.(B) -> C 。

2、內(nèi)聯(lián)函數(shù)詳解

①內(nèi)聯(lián)函數(shù)是什么

inline(小心,不是online),翻譯成“內(nèi)聯(lián)”或“內(nèi)嵌”。意指:當(dāng)編譯器發(fā)現(xiàn)某段代碼在調(diào)用一個(gè)內(nèi)聯(lián)函數(shù)時(shí),它不是去調(diào)用該函數(shù),而是將該函數(shù)的代碼,整段插入到當(dāng)前位置。這樣做的好處是省去了調(diào)用的過(guò)程,加快程序運(yùn)行速度。(函數(shù)的調(diào)用過(guò)程,由于有前面所說(shuō)的參數(shù)入棧等操作,所以總要多占用一些時(shí)間)。這樣做的不好處:由于每當(dāng)代碼調(diào)用到內(nèi)聯(lián)函數(shù),就需要在調(diào)用處直接插入一段該函數(shù)的代碼,所以程序的體積將增大。拿生活現(xiàn)象比喻,就像電視壞了,通過(guò)電話找修理工來(lái),你會(huì)嫌慢,于是干脆在家里養(yǎng)了一個(gè)修理工。這樣當(dāng)然是快了,不過(guò),修理工住在你家可就要占地兒了。內(nèi)聯(lián)函數(shù)并不是必須的,它只是為了提高速度而進(jìn)行的一種修飾。要修飾一個(gè)函數(shù)為內(nèi)聯(lián)型

使用如下格式:

inline 函數(shù)的聲明或定義

簡(jiǎn)單一句話,在函數(shù)聲明或定義前加一個(gè) inline 修飾符。

 
 
 
 
  1. inline int max(int a, int b) 
  2.  
  3.  
  4. return (a>b)? a : b; 
  5.  

內(nèi)聯(lián)函數(shù)的本質(zhì)是,節(jié)省時(shí)間但是消耗空間。

②內(nèi)聯(lián)函數(shù)規(guī)則

inline函數(shù)的規(guī)則

(1)、一個(gè)函數(shù)可以自已調(diào)用自已,稱為遞歸調(diào)用(后面講到),含有遞歸調(diào)用的函數(shù)不能設(shè)置為inline;

(2)、使用了復(fù)雜流程控制語(yǔ)句:循環(huán)語(yǔ)句和switch語(yǔ)句,無(wú)法設(shè)置為inline;

(3)、由于inline增加體積的特性,所以建議inline函數(shù)內(nèi)的代碼應(yīng)很短小。最好不超過(guò)5行。

(4)、inline僅做為一種“請(qǐng)求”,特定的情況下,編譯器將不理會(huì)inline關(guān)鍵字,而強(qiáng)制讓函數(shù)成為普通函數(shù)。出現(xiàn)這種情況,編譯器會(huì)給出警告消息。

(5)、在你調(diào)用一個(gè)內(nèi)聯(lián)函數(shù)之前,這個(gè)函數(shù)一定要在之前有聲明或已定義為inline,如果在前面聲明為普通函數(shù),而在調(diào)用代碼后面才定義為一個(gè)inline函數(shù),程序可以通過(guò)編譯,但該函數(shù)沒(méi)有實(shí)現(xiàn)inline。比如下面代碼片段:

 
 
 
 
  1. //函數(shù)一開始沒(méi)有被聲明為inline: 
  2.  
  3. void foo(); 
  4.  
  5. //然后就有代碼調(diào)用它: 
  6.  
  7. foo(); 
  8.  
  9. //在調(diào)用后才有定義函數(shù)為inline: 
  10.  
  11. inline void foo() 
  12.  
  13.  
  14. ...... 
  15.  

代碼是的foo()函數(shù)最終沒(méi)有實(shí)現(xiàn)inline;

(6)、為了調(diào)試方便,在程序處于調(diào)試階段時(shí),所有內(nèi)聯(lián)函數(shù)都不被實(shí)現(xiàn)

③內(nèi)聯(lián)函數(shù)時(shí)應(yīng)注意以下幾個(gè)問(wèn)題

(1) 在一個(gè)文件中定義的內(nèi)聯(lián)函數(shù)不能在另一個(gè)文件中使用。它們通常放在頭文件中共享。

(2) 內(nèi)聯(lián)函數(shù)應(yīng)該簡(jiǎn)潔,只有幾個(gè)語(yǔ)句,如果語(yǔ)句較多,不適合于定義為內(nèi)聯(lián)函數(shù)。

(3) 內(nèi)聯(lián)函數(shù)體中,不能有循環(huán)語(yǔ)句、if語(yǔ)句或switch語(yǔ)句,否則,函數(shù)定義時(shí)即使有inline關(guān)鍵字,編譯器也會(huì)把該函數(shù)作為非內(nèi)聯(lián)函數(shù)處理。

(4) 內(nèi)聯(lián)函數(shù)要在函數(shù)被調(diào)用之前聲明。關(guān)鍵字inline 必須與函數(shù)定義體放在一起才能使函數(shù)成為內(nèi)聯(lián),僅將inline 放在函數(shù)聲明前面不起任何作用。

3、高階函數(shù)中使用內(nèi)聯(lián)函數(shù)

直使用的 Lambda 表達(dá)式在底層被轉(zhuǎn)換成了匿名類的實(shí)現(xiàn)方式。這就表明,我們每調(diào)用一次 Lambda 表達(dá)式,都會(huì)創(chuàng)建一個(gè)新的匿名類實(shí)例,當(dāng)然也會(huì)造成額外的內(nèi)存和性能開銷。為了解決這個(gè)問(wèn)題,Kotlin 提供了內(nèi)聯(lián)函數(shù)的功能,它可以將使用 Lambda 表達(dá)式帶來(lái)的運(yùn)行時(shí)開銷完全消除,只需要在定義高階函數(shù)時(shí)加上 inline 關(guān)鍵字的聲明即可

 
 
 
 
  1. inline fun test111(num1: Int, num2: Int, block: (Int, Int) -> Int): Int { 
  2.  
  3. val result = block(num1, num2) 
  4.  
  5. return result 
  6.  

4、閉包函數(shù)

閉包函數(shù) 一個(gè)函數(shù)的返回值是函數(shù),函數(shù)的內(nèi)部包含另一個(gè)函數(shù),可以是有參無(wú)參的匿名函數(shù)

 
 
 
 
  1. fun main(args: Array) { 
  2.  
  3. val mm = aaa() 
  4.  
  5. println(mm()) 
  6.  
  7. println(mm()) 
  8.  
  9. println(mm()) 
  10.  
  11. println(mm()) 
  12.  
  13. println(mm()) 
  14.  
  15. val kk = bbb() 
  16.  
  17. println(kk("shadow")) //shadow --- 1 
  18.  
  19. println(kk("shadow")) //shadow --- 2 
  20.  
  21. println(kk("shadow")) //shadow --- 3 
  22.  
  23. println(kk("shadow")) //shadow --- 4 
  24.  
  25. println(kk("shadow")) //shadow --- 5 
  26.  
  27.  
  28. //閉包函數(shù) 就是函數(shù)作為返回參數(shù) 
  29.  
  30. fun aaa(): () -> (Int) { 
  31.  
  32. var current = 10 
  33.  
  34. return fun(): Int { 
  35.  
  36. return current++ 
  37.  
  38.  
  39.  
  40. fun bbb(): (String) -> (String) { 
  41.  
  42. var current = 0; 
  43.  
  44. return fun(str: String): String { 
  45.  
  46. current++; 
  47.  
  48. return "$str --- $current"; 
  49.  
  50.  

二、kotin中標(biāo)準(zhǔn)庫(kù)Standard.kt源碼講解

在 Kotlin 源碼的Standard.kt標(biāo)準(zhǔn)庫(kù)中提供了一些便捷的內(nèi)置高階函數(shù)( let、also、with、run、apply ),可以幫助我們寫出更簡(jiǎn)潔優(yōu)雅的 Kotlin 代碼,提高開發(fā)效率,學(xué)習(xí)源碼可以更快的幫助我們理解和應(yīng)用

1、apply

 
 
 
 
  1. @kotlin.internal.InlineOnly 
  2.  
  3. public inline fun T.apply(block: T.() -> Unit): T { 
  4.  
  5. contract { 
  6.  
  7. callsInPlace(block, InvocationKind.EXACTLY_ONCE) 
  8.  
  9.  
  10. block() 
  11.  
  12. return this 
  13.  
  • 傳遞this作為block函數(shù)參數(shù)(調(diào)用時(shí)可以省略),且apply函數(shù)的返回值是調(diào)用者本身;
  • 執(zhí)行一個(gè) T 類型中的方法,變量等,然后返回自身 T;
  • 注意參數(shù) block: T.(),但凡看到 block: T.() -> 這種代碼塊,意味著在大括號(hào) {} 中可以直接調(diào)用T內(nèi)部的 API 而不需要在加上 T. 這種【實(shí)際上調(diào)用為 this. ,this. 通常省略】
 
 
 
 
  1. val str = "hello" 
  2.  
  3. str.apply { length } //可以省略 str. 
  4.  
  5. str.apply { this.length } //可以這樣 

2、let

 
 
 
 
  1. @kotlin.internal.InlineOnly 
  2.  
  3. public inline fun 
  4.  
  5. contract { 
  6.  
  7. callsInPlace(block, InvocationKind.EXACTLY_ONCE) 
  8.  
  9.  
  10. return block(this) 
  11.  
  • let 方法是傳遞類型 T 返回另外一個(gè)類型 R 形式;
  • 傳遞it作為block函數(shù)參數(shù),且let函數(shù)的返回值是由block函數(shù)決定;

3、also

 
 
 
 
  1. @kotlin.internal.InlineOnly 
  2.  
  3. @SinceKotlin("1.1") 
  4.  
  5. public inline fun T.also(block: (T) -> Unit): T { 
  6.  
  7. contract { 
  8.  
  9. callsInPlace(block, InvocationKind.EXACTLY_ONCE) 
  10.  
  11.  
  12. block(this) 
  13.  
  14. return this 
  15.  

執(zhí)行一個(gè) T 類型中的方法,變量等,然后返回自身 T;

傳遞it作為block函數(shù)參數(shù)(調(diào)用時(shí)不可以省略),且also函數(shù)的返回值是調(diào)用者本身;

這個(gè)方法與上面的 apply 方法類似,只是在大括號(hào)中執(zhí)行 T 自身方法的時(shí)候,必須要加上 T. 否則無(wú)法調(diào)用 T 中的 API,什么意思呢?看下面代碼:

 
 
 
 
  1. val str = "hello" 
  2.  
  3. str.also { str.length } //str.必須加上,否則編譯報(bào)錯(cuò) 
  4.  
  5. str.also { it.length } //或者用 it. 

4、with

 
 
 
 
  1. @kotlin.internal.InlineOnly 
  2.  
  3. public inline fun 
  4.  
  5. contract { 
  6.  
  7. callsInPlace(block, InvocationKind.EXACTLY_ONCE) 
  8.  
  9.  
  10. return receiver.block() 
  11.  
  • with() 方法接收一個(gè)類型為 T 的參數(shù)和一個(gè)代碼塊
  • 經(jīng)過(guò)處理返回一個(gè) R 類型的結(jié)果
 
 
 
 
  1. val str = "hello" 
  2.  
  3. val ch = with(str) { 
  4.  
  5. get(0) 
  6.  
  7.  
  8. println(ch) //打印 h 

5、run

 
 
 
 
  1. @kotlin.internal.InlineOnly 
  2.  
  3. public inline fun run(block: () -> R): R { 
  4.  
  5. contract { 
  6.  
  7. callsInPlace(block, InvocationKind.EXACTLY_ONCE) 
  8.  
  9.  
  10. return block() 
  11.  
  • 要求傳遞的是一個(gè)代碼塊,同時(shí)返回一個(gè)任意類型;
  • 但凡函數(shù)接收的是一個(gè)代碼塊時(shí),使用的時(shí)候一般都建議使用 {} 來(lái)包含代碼塊中的邏輯,只有在一些特殊情況下可以參數(shù) (::fun) 的形式進(jìn)行簡(jiǎn)化
 
 
 
 
  1. @kotlin.internal.InlineOnly 
  2.  
  3. public inline fun 
  4.  
  5. contract { 
  6.  
  7. callsInPlace(block, InvocationKind.EXACTLY_ONCE) 
  8.  
  9.  
  10. return block() 
  11.  
  • 此處是執(zhí)行一個(gè) T 類型的 run 方法,傳遞的依然是一個(gè)代碼塊,
  • 只是內(nèi)部執(zhí)行的是 T 的內(nèi)部一個(gè)變量 或 方法等,返回的是 一個(gè) R 類型
 
 
 
 
  1. run { 
  2.  
  3. println(888) 
  4.  
  5.  
  6. val res = run { 2 + 3 } 
  7.  
  8. fun runDemo() { 
  9.  
  10. println("測(cè)試run方法") 
  11.  
  12.  
  13. //我們可以這么干 
  14.  
  15. run(::runDemo) 

6、takeIf

 
 
 
 
  1. public inline fun T.takeIf(predicate: (T) -> Boolean): T? { 
  2.  
  3. contract { 
  4.  
  5. callsInPlace(predicate, InvocationKind.EXACTLY_ONCE) 
  6.  
  7.  
  8. return if (predicate(this)) this else null 
  9.  
  • 根據(jù)傳遞的參數(shù) T 做內(nèi)部判斷,根據(jù)判斷結(jié)果返回 null 或者 T 自身;
  • 傳遞的是【一元謂詞】代碼塊,像極了 C++ 中的一元謂詞:方法只含有一個(gè)參數(shù),并且返回類型是Boolean類型;
  • 源碼中,通過(guò)傳遞的一元謂詞代碼塊進(jìn)行判斷,如果是 true 則返回自身,否則返回 null;
 
 
 
 
  1. val str = "helloWorld" 
  2.  
  3. str.takeIf { str.contains("hello") }?.run(::println) 

7、takeUnless

 
 
 
 
  1. public inline fun T.takeUnless(predicate: (T) -> Boolean): T? { 
  2.  
  3. contract { 
  4.  
  5. callsInPlace(predicate, InvocationKind.EXACTLY_ONCE) 
  6.  
  7.  
  8. return if (!predicate(this)) this else null 
  9.  

這個(gè)方法跟 takeIf() 方法類似,只是內(nèi)部判斷為false的時(shí)候返回自身T ,而 true 的時(shí)候返回 null,因此不過(guò)多說(shuō)明,使用參考 takeIf() 方法。

8、repeat()

 
 
 
 
  1. public inline fun repeat(times: Int, action: (Int) -> Unit) { 
  2.  
  3. contract { callsInPlace(action) } 
  4.  
  5. for (index in 0 until times) { 
  6.  
  7. action(index) 
  8.  
  9.  

分析:repeat 方法包含兩個(gè)參數(shù):

  • 第一個(gè)參數(shù)int類型,重復(fù)次數(shù),
  • 第二個(gè)參數(shù),表示要重復(fù)執(zhí)行的對(duì)象
  • 該方法每次執(zhí)行的時(shí)候都將執(zhí)行的次數(shù)傳遞給要被重復(fù)執(zhí)行的模塊,至于重復(fù)執(zhí)行模塊是否需要該值,需要根據(jù)業(yè)務(wù)實(shí)際需求考慮,例如:
 
 
 
 
  1. public inline fun repeat(times: Int, action: (Int) -> Unit) { 
  2.  
  3. contract { callsInPlace(action) } 
  4.  
  5. for (index in 0 until times) { 
  6.  
  7. action(index) 
  8.  
  9.  

三、高階函數(shù)選擇

  • 如果需要返回自身調(diào)用者本身(即return this),可以選擇 apply also
  • 如果需要傳遞this作為參數(shù),可以選擇 apply run with
  • 如果需要傳遞it作為參數(shù),可以選擇 let also
  • 如果返回值需要函數(shù)決定(即return block()),可以選擇 run with let

總結(jié)

不管是 Kotlin 中內(nèi)置的高階函數(shù),還是我們自定義的,其傳入的代碼塊樣式,無(wú)非以下幾種:

1、block: () -> T 和 block: () -> 具體類型

這種在使用 (::fun) 形式簡(jiǎn)化時(shí),要求傳入的方法必須是無(wú)參數(shù)的,返回值類型如果是T則可為任意類型,否則返回的類型必須要跟這個(gè)代碼塊返回類型一致

2、block: T.() -> R 和 block: T.() -> 具體類型

這種在使用 (::fun) 形式簡(jiǎn)化時(shí),要求傳入的方法必須包含一個(gè)T類型的參數(shù),返回值類型如果是R則可為任意類型,否則返回的類型必須要跟這個(gè)代碼塊返回類型一致。例如 with 和 apply 這兩個(gè)方法

3、block: (T) -> R 和 block: (T) -> 具體類型

這種在使用 (::fun) 形式簡(jiǎn)化時(shí),要求傳入的方法必須包含一個(gè)T類型的參數(shù),返回值類型如果是R則可為任意類型,否則返回的類型必須要跟這個(gè)代碼塊返回類型一致。例如 let 和 takeIf 這兩個(gè)方法


文章名稱:一篇帶給你Kotin高階函數(shù)詳解
路徑分享:http://www.dlmjj.cn/article/ccidpjh.html