亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > 綜合 > 正文

Kotlin中的高階函數深入講解

2024-07-21 23:03:50
字體:
來源:轉載
供稿:網友

前言

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

函數類型

在介紹常見高階函數的使用之前,有必要先了解函數類型,這對我們理解高階函數很有幫助。Kotlin 使用類似 (Int) -> String 的一系列函數類型來處理函數的聲明,這些類型具有與函數簽名相對應的特殊表示法,即它們的參數和返回值:

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

常用高階函數

Kotlin提供了很多高階函數,這里根據這些高階函數所在文件的位置,分別進行介紹,先來看一下常用的高階函數,這些高階函數在Standard.kt文件中。

1.TODO

先來看一下TODO的源碼:

/** * Always throws [NotImplementedError] stating that operation is not implemented. */@kotlin.internal.InlineOnlypublic inline fun TODO(): Nothing = throw NotImplementedError()/** * Always throws [NotImplementedError] stating that operation is not implemented. * * @param reason a string explaining why the implementation is missing. */@kotlin.internal.InlineOnlypublic inline fun TODO(reason: String): Nothing = throw NotImplementedError("An operation is not implemented: $reason")

TODO函數有兩個重載函數,都會拋出一個NotImplementedError的異常。在Java中,有時會為了保持業務邏輯的連貫性,對未實現的邏輯添加TODO標識,這些標識不進行處理,也不會導致程序的異常,但是在Kotlin中使用TODO時,就需要針對這些標識進行處理,否則當代碼邏輯運行到這些標識處時,就會出現程序的崩潰。

2.run

先給出run函數的源碼:

/** * Calls the specified function [block] and returns its result. */@kotlin.internal.InlineOnlypublic inline fun <R> run(block: () -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return block()}/** * Calls the specified function [block] with `this` value as its receiver and returns its result. */@kotlin.internal.InlineOnlypublic inline fun <T, R> T.run(block: T.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return block()}

這兩個run函數都接收一個lambda表達式,執行傳入的lambda表達式,并且返回lambda表達式的執行結果。區別是T.run()是作為泛型T的一個擴展函數,所以在傳入的lambda表達式中可以使用this關鍵字來訪問這個泛型T中的成員變量和成員方法。

比如,對一個EditText控件,進行一些設置時:

//email 是一個EditText控件email.run {   this.setText("請輸入郵箱地址")  setTextColor(context.getColor(R.color.abc_btn_colored_text_material))}

3.with

先看一下with函數的源碼:

/** * Calls the specified function [block] with the given [receiver] as its receiver and returns its result. */@kotlin.internal.InlineOnlypublic inline fun <T, R> with(receiver: T, block: T.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return receiver.block()}

with函數有兩個參數,一個類型為泛型T類型的receiver,和一個lambda表達式,這個表達式會作為receiver的擴展函數來執行,并且返回lambda表達式的執行結果。

with函數與T.run函數只是寫法上的不同,比如上面的示例可以用with函數:

 with(email, {  setText("請輸入郵箱地址")  setTextColor(context.getColor(R.color.abc_btn_colored_text_material)) })  //可以進一步簡化為 with(email) {  setText("請輸入郵箱地址")  setTextColor(context.getColor(R.color.abc_btn_colored_text_material)) }

4.apply

看一下apply函數的源碼:

/** * Calls the specified function [block] with `this` value as its receiver and returns `this` value. */@kotlin.internal.InlineOnlypublic inline fun <T> T.apply(block: T.() -> Unit): T { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } block() return this}

apply函數作為泛型T的擴展函數,接收一個lambda表達式,表達式的receiver是泛型T,沒有返回值,apply函數返回泛型T對象本身??梢钥吹絋.run()函數也是接收lambda表達式,但是返回值是lambda表達式的執行結果,這是與apply函數最大的區別。

還是上面的示例,可以用apply函數:

 email.apply {   setText("請輸入郵箱地址") }.apply {  setTextColor(context.getColor(R.color.abc_btn_colored_text_material)) }.apply {   setOnClickListener {   TODO()  } }

5.also

看一下also函數的源碼:

/** * Calls the specified function [block] with `this` value as its argument and returns `this` value. */@kotlin.internal.InlineOnly@SinceKotlin("1.1")public inline fun <T> T.also(block: (T) -> Unit): T { contract {  callsInPlace(block, InvocationKind.EXACTLY_ONCE) } block(this) return this}

與apply函數類似,也是作為泛型T的擴展函數,接收一個lambda表達式,lambda表達式沒有返回值。also函數也返回泛型T對象本身,不同的是also函數接收的lambda表達式需要接收一個參數T,所以在lambda表達式內部,可以使用it,而apply中只能使用this。

關于this和it的區別,總結一下:

  • 如果泛型T,作為lambda表達式的參數,形如:(T) -> Unit,此時在lambda表示內部使用it;
  • 如果泛型T,作為lambda表達式的接收者,形如:T.() -> Unit,此時在lambda表達式內部使用this;
  • 不論this,還是it,都代表T對象,區別是it可以使用其它的名稱代替。

還是上面的示例,如果用also函數:

 email.also {    it.setText("請輸入郵箱地址")  }.also {    //可以使用其它名稱   editView -> editView.setTextColor(applicationContext.getColor(R.color.abc_btn_colored_text_material))  }.also {    it.setOnClickListener {     //TODO   }  }

6.let

看一下let函數的源碼:

/** * Calls the specified function [block] with `this` value as its argument and returns its result. */@kotlin.internal.InlineOnlypublic inline fun <T, R> T.let(block: (T) -> R): R { contract {  callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return block(this)}

let函數作為泛型T的擴展函數,接收一個lambda表達式,lambda表達式需要接收一個參數T,存在返回值。lambda表達式的返回值就是let函數的返回值。由于lambda表達式接受參數T,所以也可以在其內部使用it。

let應用最多的場景是用來判空,如果上面示例中的EditText是自定義的可空View,那么使用let就非常方便:

 var email: EditText? = null  TODO()  email?.let {    email.setText("請輸入郵箱地址")   email.setTextColor(getColor(R.color.abc_btn_colored_text_material))  }

7.takeIf

看一下takeIf函數的源碼:

/** * Returns `this` value if it satisfies the given [predicate] or `null`, if it doesn't. */@kotlin.internal.InlineOnly@SinceKotlin("1.1")public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? { contract {  callsInPlace(predicate, InvocationKind.EXACTLY_ONCE) } return if (predicate(this)) this else null}

takeIf函數作為泛型T的擴展函數,接受一個lambda表達式,lambda表達式接收一個參數T,返回Boolean類型,takeIf函數根據接收的lambda表達式的返回值,決定函數的返回值,如果lambda表達式返回true,函數返回T對象本身,如果lambda表達式返回false,函數返回null。

還是上面的示例,假設用戶沒有輸入郵箱地址,進行信息提示:

 email.takeIf {    email.text.isEmpty()  }?.setText("郵箱地址不能為空")

8.takeUnless

給出takeUnless函數的源碼:

/** * Returns `this` value if it _does not_ satisfy the given [predicate] or `null`, if it does. */@kotlin.internal.InlineOnly@SinceKotlin("1.1")public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? { contract {  callsInPlace(predicate, InvocationKind.EXACTLY_ONCE) } return if (!predicate(this)) this else null}

takeUnless函數與takeIf函數類似,唯一的區別是邏輯相反,takeUnless函數根據lambda表達式的返回值決定函數的返回值,如果lambda表達式返回true,函數返回null,如果lambda表達式返回false,函數返回T對象本身。

還是上面的示例,如果用takeUnless實現,就需要調整一下邏輯:

  email.takeUnless {   email.text.isNotEmpty() //與takeIf的區別  }?.setText("郵箱地址不能為空")

9.repeat

給出repeat函數的源碼:

/** * Executes the given function [action] specified number of [times]. * * A zero-based index of current iteration is passed as a parameter to [action]. */@kotlin.internal.InlineOnlypublic inline fun repeat(times: Int, action: (Int) -> Unit) { contract { callsInPlace(action) } for (index in 0 until times) {  action(index) }}

repeat函數接收兩個參數,一個Int型參數times表示重復次數,一個lambda表達式,lambda表達式接收一個Int型參數,無返回值。repeat函數就是將我們傳入的lambda表達式執行times次。

 repeat(3) {  println("執行第${it + 1}次") }  //運行結果執行第1次執行第2次執行第3次

由于repeat函數接收的lambda表達式,需要一個Int型參數,因此在表達式內部使用it,其實it就是for循環的索引,從0開始。

總結

最后對這些高階函數做一下總結,TODO對比Java中的TODO,需要實現業務邏輯,不能放任不理,否則會出現異常,導致崩潰。takeIf、takeUnless這一對都是根據接收lambda表達式的返回值,決定函數的最終返回值是對象本身,還是null,區別是takeIf,如果lambda表達式返回true,返回對象本身,否則返回null;takeUnless與takeIf的邏輯正好相反,如果lambda表達式返回true,返回null,否則返回對象本身。repeat函數,見名知意,將接收的lambda表達式重復執行指定次。

run、with、apply、also、let這幾個函數區別不是很明顯,有時候使用其中一個函數實現的邏輯,完全也可以用另外一個函數實現,具體使用哪一個,根據個人習慣。需要注意的是:

  • 對作為擴展函數的高階函數,使用前需要判斷接收的對象是否為空,比如T.run,apply,also,let在使用前需要進行空檢查;
  • 對于返回對象本身的函數,比如apply,also可以形成鏈式調用;
  • 對于在函數內部能夠使用it的函數,it可以用意思更加清晰的變量代替,比如T.run,also,let。

對這幾個函數的區別做一個對比:

函數名稱 是否作為擴展函數 是否返回對象本身 在函數內部使用this/ it
run no no -
T.run yes no it
with no no this
apply yes yes this
also yes yes it
let yes no it

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VeVb武林網的支持。


注:相關教程知識閱讀請移步到kotlin教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久av中文字幕| 亚洲成人免费在线视频| 欧美日韩国产999| 最近免费中文字幕视频2019| 久久夜色精品国产欧美乱| 欧美久久精品一级黑人c片| 精品福利视频导航| 久久久久久久影院| www.xxxx欧美| 97精品免费视频| 亚洲视频视频在线| 日韩视频在线免费观看| 精品中文视频在线| 97成人在线视频| 日韩欧美国产黄色| 一区二区av在线| 欧美性做爰毛片| 在线视频欧美日韩精品| 欧美日韩一区二区在线| 91精品91久久久久久| 在线日韩精品视频| 亚洲人成网站色ww在线| 亚洲第一网站免费视频| 欧美视频免费在线观看| 91香蕉嫩草影院入口| 一区二区三区视频免费在线观看| 国产免费一区二区三区在线能观看| 91久久国产婷婷一区二区| 日韩av免费一区| 亚洲毛茸茸少妇高潮呻吟| 国内精品视频久久| 国产欧美久久久久久| 国产精品视频午夜| 欧美专区国产专区| 2020欧美日韩在线视频| 国产精品露脸自拍| 国产精品久久久av久久久| 久久精品视频导航| 欧美一级视频一区二区| 国产精自产拍久久久久久| 国产欧美日韩精品丝袜高跟鞋| 亚洲三级 欧美三级| 亚洲天堂男人天堂| 亚洲黄色有码视频| 在线观看日韩欧美| www.99久久热国产日韩欧美.com| 日韩国产高清视频在线| 国产脚交av在线一区二区| 亚洲成人av资源网| 在线观看国产精品淫| 欧美色欧美亚洲高清在线视频| 青青草国产精品一区二区| 中文字幕av一区二区三区谷原希美| 91精品久久久久久久久久另类| 欧美日韩国产影院| 欧美xxxx综合视频| 欧美午夜女人视频在线| 成人免费看黄网站| 午夜精品一区二区三区在线视| 69国产精品成人在线播放| 亚洲视频电影图片偷拍一区| 精品日韩美女的视频高清| 欧美在线国产精品| www日韩中文字幕在线看| 亚洲人成在线一二| 久久久久久免费精品| 亚洲精品永久免费| 欧美一级大片视频| 国产欧美精品xxxx另类| 国产精品最新在线观看| 日韩在线免费视频| 久久精品免费电影| 欧美日韩黄色大片| 欧美日韩在线视频一区二区| 日韩av在线高清| 青草成人免费视频| 日韩在线观看免费av| 91精品久久久久久久久久久久久| 78m国产成人精品视频| 欧美大片在线免费观看| 国产精品激情av在线播放| 日韩精品在线免费观看视频| 日韩视频欧美视频| 国产aaa精品| 中文字幕在线观看亚洲| 98视频在线噜噜噜国产| 国产成人亚洲精品| 国产+人+亚洲| 亚洲精品久久久久国产| 日本精品中文字幕| 国产精品久久久久久网站| 亚洲最新中文字幕| 欧美精品九九久久| 亚洲欧美激情另类校园| 日韩中文字幕亚洲| 亚洲999一在线观看www| 麻豆精品精华液| 久热精品视频在线观看一区| 亚洲xxxxx性| 久久天天躁狠狠躁夜夜爽蜜月| 成人午夜激情网| 日韩国产欧美精品一区二区三区| 国产在线观看不卡| 亚洲精品98久久久久久中文字幕| 欧美精品日韩www.p站| 91在线免费视频| 成人国产在线视频| 国产精品免费一区二区三区都可以| 亚洲a中文字幕| 91精品国产综合久久香蕉| 亚洲乱亚洲乱妇无码| 色与欲影视天天看综合网| 91色在线观看| 亚洲第一黄色网| 激情久久av一区av二区av三区| 在线成人中文字幕| 欧美日韩国产丝袜另类| 久久久久久久久电影| 欧美一级高清免费播放| 久久精品一本久久99精品| 97在线看免费观看视频在线观看| 韩国v欧美v日本v亚洲| 狠狠躁夜夜躁人人爽天天天天97| 国产日本欧美在线观看| 久久视频在线直播| 欧美日韩激情视频8区| 黑人巨大精品欧美一区二区三区| 国产精品久久久久久久久久ktv| 欧美黑人巨大精品一区二区| 国产欧美精品久久久| 在线亚洲男人天堂| 国产精品老女人视频| 欧美日韩性视频| 欧美大片免费观看| 久久天天躁狠狠躁夜夜躁2014| 国产中文字幕亚洲| 久久av中文字幕| 亚洲天堂av高清| 7777精品视频| 欧美日韩国产成人在线| 国产精品久久久久久久一区探花| 欧美日韩中文字幕| 亚洲日本成人网| 色偷偷av一区二区三区乱| 久久精品视频播放| 在线看国产精品| 亚洲精品国产综合区久久久久久久| 亚洲图片欧洲图片av| 日本人成精品视频在线| 久久久久国产精品一区| 欧美极品美女视频网站在线观看免费| 亚洲欧美日本另类| 日韩精品在线看| 日本欧美国产在线| 欧美亚洲另类在线| 国产91亚洲精品| 中文字幕av一区二区三区谷原希美| 国产精品xxxxx| 日韩av一区在线观看| 国产欧美一区二区三区视频| 欧美专区在线观看| 成人久久精品视频| 国产99视频精品免视看7| 亚洲伊人久久综合|