溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Kotlin中標(biāo)準(zhǔn)函數(shù)run、with、let、also與apply有哪些區(qū)別

發(fā)布時(shí)間:2021-06-17 14:36:50 來(lái)源:億速云 閱讀:367 作者:小新 欄目:移動(dòng)開(kāi)發(fā)

這篇文章給大家分享的是有關(guān)Kotlin中標(biāo)準(zhǔn)函數(shù)run、with、let、also與apply有哪些區(qū)別的內(nèi)容。小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧。

前言

和Java相比,在Kotlin中提供了不少新的特性。這次我們就來(lái)聊一聊Kotlin的一些通用的擴(kuò)展標(biāo)準(zhǔn)函數(shù)run,with,let,also和apply。對(duì)于這五個(gè)標(biāo)準(zhǔn)函數(shù)它們都存在于Kotlin的源碼標(biāo)準(zhǔn)庫(kù)當(dāng)中,也就是在Standard.kt文件當(dāng)中。它們都是適用于任何對(duì)象的通用擴(kuò)展函數(shù)。但是對(duì)于run,with,let,also和apply這五個(gè)函數(shù)他們的用法及其相似,以至于我們無(wú)法確定去選擇使用哪一個(gè)。那么現(xiàn)在我們就來(lái)聊一下這五個(gè)函數(shù)它們的使用方法,它們的不同之處以及在什么場(chǎng)景下去使用。

作用域函數(shù)

在這里我們重點(diǎn)是看一下run,with,T.run,T.let,T.also,和T.apply,對(duì)于這幾個(gè)函數(shù)來(lái)說(shuō)它們最重要的功能之一是在調(diào)用函數(shù)的內(nèi)部又提供了一個(gè)作用域。

那么下面就通過(guò)一段代碼來(lái)看一下run函數(shù)的作用域,對(duì)于其它函數(shù)來(lái)說(shuō)當(dāng)然也是類似。

fun test(){
 var animal = "cat"
 run {
  val animal = "dog"
  println(animal) // dog
 }
 println(animal)  //cat
}

在這個(gè)簡(jiǎn)單的test函數(shù)當(dāng)中我們擁有一個(gè)單獨(dú)的作用域,在run函數(shù)中能夠重新定義一個(gè)animal變量,并且它的作用域只存在于run函數(shù)當(dāng)中。

目前對(duì)于這個(gè)run函數(shù)看起來(lái)貌似沒(méi)有什么用處,但是在run函數(shù)當(dāng)中它不僅僅只是一個(gè)作用域,他還有一個(gè)返回值。他會(huì)返回在這個(gè)作用域當(dāng)中的最后一個(gè)對(duì)象。

例如現(xiàn)在有這么一個(gè)場(chǎng)景,用戶領(lǐng)取app的獎(jiǎng)勵(lì),如果用戶沒(méi)有登錄彈出登錄dialog,如果已經(jīng)登錄則彈出領(lǐng)取獎(jiǎng)勵(lì)的dialog。我們可以使用以下代碼來(lái)處理這個(gè)邏輯。

run {
 if (islogin) loginDialog else getAwardDialog
}.show()

可以看到上面這段代碼會(huì)變得更加的簡(jiǎn)潔,并且可以將show方法一次應(yīng)用到上面兩個(gè)dialog當(dāng)中,而不是去調(diào)用兩次。

with和其它通用標(biāo)準(zhǔn)函數(shù)

在這里之所以將with函數(shù)單獨(dú)拿出來(lái)進(jìn)行說(shuō)明,是因?yàn)閣ith得用法和其它通用的標(biāo)準(zhǔn)函數(shù)的用法比較獨(dú)特。在這里我們依然使用run函數(shù)來(lái)進(jìn)行對(duì)比。對(duì)于下面這段代碼做的是同樣一件事。它們的不同之處就是一個(gè)使用了with(T)函數(shù),而另一個(gè)則是使用了T.run函數(shù)。

with(webView.settings){
 javaScriptEnabled = true
 databaseEnabled = true
}
webView.settings.run { 
 javaScriptEnabled = true
 databaseEnabled = true
}

但是我們覺(jué)得使用哪一個(gè)會(huì)更好呢?現(xiàn)在假設(shè)一種場(chǎng)景,那就是webView.settings可能為null。那我們就來(lái)再次看一下下面這段代碼.

with(webView.settings){
 javaScriptEnabled = true
 databaseEnabled = true
}
webView.settings?.run { 
 javaScriptEnabled = true
 databaseEnabled = true
}

這么以來(lái)就很明顯了,當(dāng)然是T.run方法會(huì)更好,因?yàn)槲覀兛梢栽谑褂眠@些函數(shù)之前可以進(jìn)行對(duì)null的檢查。

對(duì)于with也是存在一個(gè)返回值,它也是會(huì)返回在這個(gè)作用域當(dāng)中的最后一個(gè)對(duì)象。

作用域中接收者this和it

在這幾個(gè)擴(kuò)展函數(shù)當(dāng)中,它們都能直接獲取到調(diào)用的對(duì)象或者是with中傳入?yún)?shù)的對(duì)象。在這五個(gè)擴(kuò)展函數(shù)在它們的作用域中的接收者可以是this或者是it。那么我們來(lái)對(duì)比一下T.run和T.let函數(shù)。這兩個(gè)函數(shù)也是十分的相似。

stringVariable?.run {
 println("字符串的長(zhǎng)度為$length")
}

stringVariable?.let {
 println("字符串的長(zhǎng)度為 ${it.length}")
}

在這兩段代碼中可以清晰的看到。在T.run函數(shù)中通過(guò)this來(lái)獲取stringVariable對(duì)象,而在T.let函數(shù)中通過(guò)it來(lái)取出stringVariable對(duì)象。當(dāng)然我們也能夠?yàn)閕t重新命名。如果我們不想覆蓋外部作用域的this,這時(shí)候去使用T.let會(huì)更加的方便。至于哪些函數(shù)的接收者是this,哪些函數(shù)的接收者是it,在后面會(huì)通過(guò)一張樹(shù)狀圖清晰的體現(xiàn)出來(lái)。

在作用域中返回值的類型

在這些作用域中它們都會(huì)存在一個(gè)返回值。在上面的講述的run,with,T.run,T.let中它們返回的都是作用域中最后一個(gè)對(duì)象。當(dāng)然它們所返回的值是允許和接受者it或者this對(duì)象的類型不同。但是并不是所有的標(biāo)準(zhǔn)函數(shù)都是返回作用域的最后一個(gè)對(duì)象。例如T.also函數(shù)。

val original = "abc"
original.let {
 println("The original String is $it") // "abc"
 it.reversed() 
}.let {
 println("The reverse String is $it") // "cba"
 it.length 
}.let {
 println("The length of the String is $it") // 3
}

original.also {
 println("The original String is $it") // "abc"
 it.reversed() 
}.also {
 println("The reverse String is ${it}") // "abc"
 it.length 
}.also {
 println("The length of the String is ${it}") // "abc"
}

從上面兩段代碼可以看出T.let和T.also的返回值使不同的。T.let返回的是作用域中的最后一個(gè)對(duì)象,它的值和類型都可以改變。但是T.also不管調(diào)用多少次返回的都是原來(lái)的original對(duì)象。

對(duì)于T.let和T.also都能夠進(jìn)行鏈?zhǔn)讲僮鳎敲次覀儸F(xiàn)在結(jié)合一下T.let和T.also的鏈?zhǔn)秸{(diào)用來(lái)看一下在實(shí)際場(chǎng)景中的應(yīng)用。

//原始函數(shù)
fun makeDir(path: String): File {
 val result = File(path)
 result.mkdirs()
 return result
}

//通過(guò)let和also的鏈?zhǔn)秸{(diào)用改進(jìn)后的函數(shù)
fun makeDir(path: String) = path.let{ File(it) }.also{ it.mkdirs() }

擴(kuò)展函數(shù)的特性

到目前為止除了T.apply沒(méi)有使用到以外,根據(jù)上面的用法我們可以總結(jié)出來(lái)這些標(biāo)準(zhǔn)函數(shù)的三大特性。

  • 它們都有自己的作用域

  • 它們作用域中的接收者是this或者it

  • 它們都有一個(gè)返回值,返回最后一個(gè)對(duì)象(this)或者調(diào)用者自身(itself)

由此可想到對(duì)于T.apply無(wú)非也就是這三個(gè)特性。對(duì)于T.apply它作用域中的接收者是this,并且返回的調(diào)用者T。因此,T.apply的其中一個(gè)使用場(chǎng)景可以用來(lái)創(chuàng)建一個(gè)Fragment,代碼如下所示:

// 使用普通的方法創(chuàng)建一個(gè)Fragment
fun createInstance(args: Bundle) : MyFragment {
 val fragment = MyFragment()
 fragment.arguments = args
 return fragment
}

// 通過(guò)apply來(lái)改善原有的方法創(chuàng)建一個(gè)Fragment
fun createInstance(args: Bundle) 
    = MyFragment().apply { arguments = args }

我們也能夠通過(guò)T.apply的鏈?zhǔn)秸{(diào)用創(chuàng)建一個(gè)Intent:

// 普通創(chuàng)建Intent方法
fun createIntent(intentData: String, intentAction: String): Intent {
 val intent = Intent()
 intent.action = intentAction
 intent.data=Uri.parse(intentData)
 return intent
}

// 通過(guò)apply函數(shù)的鏈?zhǔn)秸{(diào)用創(chuàng)建Intent
fun createIntent(intentData: String, intentAction: String) =
  Intent().apply { action = intentAction }
    .apply { data = Uri.parse(intentData) }

如何選擇使用

在這里我們通過(guò)一個(gè)樹(shù)狀圖來(lái)看一下對(duì)著五個(gè)標(biāo)準(zhǔn)函數(shù)的區(qū)別,使用以及如何選取標(biāo)準(zhǔn)函數(shù)(圖片來(lái)源于參考文獻(xiàn)當(dāng)中)

Kotlin中標(biāo)準(zhǔn)函數(shù)run、with、let、also與apply有哪些區(qū)別

總結(jié)

在這里做一下總結(jié),我們可以看出在這五個(gè)通用標(biāo)準(zhǔn)函數(shù)當(dāng)中它們的特性也是十分的簡(jiǎn)單,無(wú)非也就是接收者和返回值的不同。對(duì)于with,T.run,T.apply接收者是this,而T.let和T.also接受者是it;對(duì)于with,T.run,T.let返回值是作用域的最后一個(gè)對(duì)象(this),而T.apply和T.also返回值是調(diào)用者本身(itself)。

感謝各位的閱讀!關(guān)于“Kotlin中標(biāo)準(zhǔn)函數(shù)run、with、let、also與apply有哪些區(qū)別”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI