欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Kotlin作用域函數(shù)之間的區(qū)別和使用場景詳解

 更新時間:2020年08月24日 09:03:42   作者:H_Cheng  
這篇文章主要給大家介紹了關(guān)于Kotlin作用域函數(shù)之間的區(qū)別和使用場景的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

作用域函數(shù)

Kotlin 的作用域函數(shù)有五種:let、run、with、apply 以及 also。

這些函數(shù)基本上做了同樣的事情:在一個對象上執(zhí)行一個代碼塊。

下面是作用域函數(shù)的典型用法:

val adam = Person("Adam").apply { 
 age = 20
 city = "London"
}
println(adam)

如果不使用 apply 來實現(xiàn),每次給新創(chuàng)建的對象屬性賦值時就必須重復(fù)其名稱。

val adam = Person("Adam")
adam.age = 20
adam.city = "London"
println(adam)

作用域函數(shù)沒有引入任何新的技術(shù),但是它們可以使你的代碼更加簡潔易讀。

事實上,同樣的功能可能多個作用域函數(shù)都能實現(xiàn),但我們應(yīng)該根據(jù)不同的場景和需求來使用合適的作用域函數(shù),以求更優(yōu)雅的實現(xiàn)。

如果想直接查看作用域函數(shù)之間的區(qū)別與使用場景歸納表,請點擊這里

下面我們將詳細描述這些作用域函數(shù)的區(qū)別及約定用法。

區(qū)別

作用域函數(shù)之間有兩個主要區(qū)別:

  • 引用上下文對象的方式
  • 返回值

引用上下文對象的方式:this 還是 it

在作用域函數(shù)的 lambda 表達式里,上下文對象可以不使用其實際名稱而是使用一個更簡短的引用(this 或 it)來訪問。
作用域函數(shù)引用上下文對象有兩種方式:

  • 作為 lambda 表達式的接收者(this): run、with、apply
  • 作為 lambda 表達式的參數(shù)(it): let、also
fun main() {
 val str = "Hello"
 // this
 str.run {
 println("The receiver string length: $length")
 //println("The receiver string length: ${this.length}") // 和上句效果相同
 }

 // it
 str.let {
 println("The receiver string's length is ${it.length}")
 }
}

作為 lambda 表達式的接收者

run、with 以及 apply 將上下文對象作為 lambda 表達式接收者,通過關(guān)鍵字 this 引用上下文對象??梢允÷?this,使代碼更簡短。

使用場景:主要對上下文對象的成員進行操作(訪問屬性或調(diào)用函數(shù))。

val adam = Person("Adam").apply { 
 age = 20  // 和 this.age = 20 或者 adam.age = 20 一樣
 city = "London"
}
println(adam)

作為 lambda 表達式的參數(shù)

let 及 also 將上下文對象作為 lambda 表達式參數(shù)。如果沒有指定參數(shù)名,對象可以用隱式默認名稱 it 訪問。it 比 this 簡短,帶有 it 的表達式通常更容易閱讀。然而,當調(diào)用對象函數(shù)或?qū)傩詴r,不能像 this 這樣隱式地訪問對象。

使用場景:主要對上下文對象進行操作,作為參數(shù)使用。

fun getRandomInt(): Int {
 return Random.nextInt(100).also {
 writeToLog("getRandomInt() generated value $it")
 }
}
val i = getRandomInt()

此外,當將上下文對象作為參數(shù)傳遞時,可以為上下文對象指定在作用域內(nèi)的自定義名稱(為了提高代碼的可讀性)。

fun getRandomInt(): Int {
 return Random.nextInt(100).also { value ->
 writeToLog("getRandomInt() generated value $value")
 }
}
val i = getRandomInt()

返回值

根據(jù)返回結(jié)果,作用域函數(shù)可以分為以下兩類:

  • 返回上下文對象:apply、also
  • 返回 lambda 表達式結(jié)果:let、run、with

可以根據(jù)在代碼中的后續(xù)操作來選擇適當?shù)暮瘮?shù)。

返回上下文對象

apply 及 also 的返回值是上下文對象本身。因此,它們可以作為輔助步驟包含在調(diào)用鏈中:你可以繼續(xù)在同一個對象上進行鏈式函數(shù)調(diào)用。

val numberList = mutableListOf<Double>()
numberList.also { println("Populating the list") }
 .apply {
 add(2.71)
 add(3.14)
 add(1.0)
 }
 .also { println("Sorting the list") }
 .sort()

它們還可以用在返回上下文對象的函數(shù)的 return 語句中。

fun getRandomInt(): Int {
 return Random.nextInt(100).also {
 writeToLog("getRandomInt() generated value $it")
 }
}

val i = getRandomInt()

返回lambda表達式結(jié)果

let、run 及 with 返回 lambda 表達式的結(jié)果。所以,在需要使用其結(jié)果給一個變量賦值,或者在需要對其結(jié)果進行鏈式操作等情況下,可以使用它們。

val numbers = mutableListOf("one", "two", "three")
val countEndsWithE = numbers.run { 
 add("four")
 add("five")
 count { it.endsWith("e") }
}
println("There are $countEndsWithE elements that end with e.")

此外,還可以忽略返回值,僅使用作用域函數(shù)為變量創(chuàng)建一個臨時作用域。

val numbers = mutableListOf("one", "two", "three")
with(numbers) {
 val firstItem = first()
 val lastItem = last() 
 println("First item: $firstItem, last item: $lastItem")
}

約定用法

let

上下文對象 作為 lambda 表達式的 參數(shù)(it)來訪問。 返回值 是 lambda 表達式的結(jié)果。

let 可用于在調(diào)用鏈的結(jié)果上調(diào)用一個或多個函數(shù)。例如,以下代碼打印對集合的兩個操作的結(jié)果:

val numbers = mutableListOf("one", "two", "three", "four", "five")
val resultList = numbers.map { it.length }.filter { it > 3 }
println(resultList)

使用 let,可以寫成這樣:

val numbers = mutableListOf("one", "two", "three", "four", "five")
numbers.map { it.length }.filter { it > 3 }.let { 
 println(it)
 // 如果需要可以調(diào)用更多函數(shù)
} 

若代碼塊僅包含以 it 作為參數(shù)的單個函數(shù),則可以使用方法引用(::)代替 lambda 表達式:

val numbers = mutableListOf("one", "two", "three", "four", "five")
numbers.map { it.length }.filter { it > 3 }.let(::println)

let 經(jīng)常用于 僅使用非空值執(zhí)行代碼塊。如需對非空對象執(zhí)行操作,可對其使用安全調(diào)用操作符 ?. 并調(diào)用 let 在 lambda 表達式中執(zhí)行操作。

val str: String? = "Hello" 
//processNonNullString(str) // 編譯錯誤:str 可能為空
val length = str?.let { 
 println("let() called on $it")
 processNonNullString(it) // 編譯通過:'it' 在 '?.let { }' 中必不為空
 it.length
}

使用 let 的另一種情況是引入作用域受限的局部變量以提高代碼的可讀性。如需為上下文對象定義一個新變量,可提供其名稱作為 lambda 表達式參數(shù)來替默認的 it。

val numbers = listOf("one", "two", "three", "four")
val modifiedFirstItem = numbers.first().let { firstItem ->
 println("The first item of the list is '$firstItem'")
 if (firstItem.length >= 5) firstItem else "!" + firstItem + "!"
}.toUpperCase()
println("First item after modifications: '$modifiedFirstItem'")

with

一個非擴展函數(shù):上下文對象作為參數(shù)傳遞,但是在 lambda 表達式內(nèi)部,它可以作為接收者(this)使用。 返回值是lambda 表達式結(jié)果。

建議使用 with 來調(diào)用上下文對象上的函數(shù),而不使用 lambda 表達式結(jié)果。 在代碼中,with 可以理解為“對于這個對象,執(zhí)行以下操作。”

val numbers = mutableListOf("one", "two", "three")
with(numbers) {
 println("'with' is called with argument $this")
 println("It contains $size elements")
}

with 的另一個使用場景是引入一個輔助對象,其屬性或函數(shù)將用于計算一個值。

val numbers = mutableListOf("one", "two", "three")
val firstAndLast = with(numbers) {
 "The first element is ${first()}," +
 " the last element is ${last()}"
}
println(firstAndLast)

run

上下文對象 作為 接收者(this)來訪問。 返回值 是 lambda 表達式結(jié)果。

run 和 with 做同樣的事情,但是調(diào)用方式和 let 一樣——作為上下文對象的擴展函數(shù).

當 lambda 表達式同時包含對象初始化和返回值的計算時,run 很有用。

val service = MultiportService("https://example.kotlinlang.org", 80)
val result = service.run {
 port = 8080
 query(prepareRequest() + " to port $port")
}
// 同樣的代碼如果用 let() 函數(shù)來寫:
val letResult = service.let {
 it.port = 8080
 it.query(it.prepareRequest() + " to port ${it.port}")
}

除了在接收者對象上調(diào)用 run 之外,還可以將其用作非擴展函數(shù)。 非擴展 run 可以使你在需要表達式的地方執(zhí)行一個由多個語句組成的塊。

val hexNumberRegex = run {
 val digits = "0-9"
 val hexDigits = "A-Fa-f"
 val sign = "+-"
 Regex("[$sign]?[$digits$hexDigits]+")
}
for (match in hexNumberRegex.findAll("+1234 -FFFF not-a-number")) {
 println(match.value)
}

apply

上下文對象 作為 接收者(this)來訪問。返回值 是上下文對象本身。

對于不返回值且主要在接收者(this)對象的成員上運行的代碼塊使用 apply。apply 的常見情況是對象配置。這樣的調(diào)用可以理解為“將以下賦值操作應(yīng)用于對象”。

val adam = Person("Adam").apply {
 age = 32
 city = "London" 
}
println(adam)

將接收者作為返回值,可以輕松地將 apply 包含到調(diào)用鏈中以進行更復(fù)雜的處理。

also

上下文對象作為 lambda 表達式的參數(shù)(it)來訪問。 返回值 是上下文對象本身。

also 對于執(zhí)行一些將上下文對象作為參數(shù)的操作很有用。 對于需要引用對象而不是其屬性與函數(shù)的操作,或者不想屏蔽來自外部作用域的 this 引用時,請使用 also。

當在代碼中看到 also 時,可以將其理解為“并且用該對象執(zhí)行以下操作”。

val numbers = mutableListOf("one", "two", "three")
numbers
 .also { println("The list elements before adding new one: $it") }
 .add("four")

總結(jié)

下表總結(jié)了Kotlin作用域函數(shù)的主要區(qū)別與使用場景:

函數(shù) 對象引用 返回值 是否是擴展函數(shù) 使用場景
let it Lambda 表達式結(jié)果 1. 對一個非空對象執(zhí)行 lambda 表達式
2. 將表達式作為變量引入為局部作用域中
run this Lambda 表達式結(jié)果 對象配置并且計算結(jié)果
run - Lambda 表達式結(jié)果 不是:調(diào)用無需上下文對象 在需要表達式的地方運行語句
with this Lambda 表達式結(jié)果 不是:把上下文對象當做參數(shù) 一個對象的一組函數(shù)調(diào)用
apply this 上下文對象 對象配置
also it 上下文對象 附加效果

參考資料

Kotlin語言中文網(wǎng)

好了,到此這篇關(guān)于Kotlin作用域函數(shù)之間的區(qū)別和使用場景的文章就介紹到這了,更多相關(guān)Kotlin作用域函數(shù)區(qū)別與使用場景內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android編程之高效開發(fā)App的10個建議

    Android編程之高效開發(fā)App的10個建議

    這篇文章主要介紹了Android編程之高效開發(fā)App的10個建議,較為詳細的分析了Android開發(fā)中的常見問題與注意事項,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-10-10
  • Android APT 實現(xiàn)控件注入框架SqInject的示例

    Android APT 實現(xiàn)控件注入框架SqInject的示例

    這篇文章主要介紹了Android APT 實現(xiàn)控件注入框架SqInject的示例,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下
    2021-03-03
  • Android RecyclerView添加FootView和HeadView

    Android RecyclerView添加FootView和HeadView

    這篇文章主要介紹了Android RecyclerView添加FootView和HeadView的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • Android Studio+Servlet+MySql實現(xiàn)登錄注冊

    Android Studio+Servlet+MySql實現(xiàn)登錄注冊

    對于大多數(shù)的APP都有登錄注冊這個功能,本文就來介紹一下Android Studio+Servlet+MySql實現(xiàn)登錄注冊,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • Android 單雙擊實現(xiàn)的方法步驟

    Android 單雙擊實現(xiàn)的方法步驟

    這篇文章主要介紹了Android 單雙擊實現(xiàn)的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • Android編程實現(xiàn)Toast只顯示最后一條的方法

    Android編程實現(xiàn)Toast只顯示最后一條的方法

    這篇文章主要介紹了Android編程實現(xiàn)Toast只顯示最后一條的方法,結(jié)合實例形式總結(jié)了Toast只顯示最后一條的原理與具體實現(xiàn)技巧,需要的朋友可以參考下
    2017-08-08
  • android4.0混淆XmlPullParser報錯原因分析解決

    android4.0混淆XmlPullParser報錯原因分析解決

    今天,用android4.0在proguard-project.txt中加入 -libraryjars libs/ksoap2-android-assembly-2.6.0-jar-with-dependencies.jar這句話后,混淆時報上面的錯誤,下面與大家分享下具體的解決方法
    2013-06-06
  • Android 兩個Service的相互監(jiān)視實現(xiàn)代碼

    Android 兩個Service的相互監(jiān)視實現(xiàn)代碼

    這篇文章主要介紹了Android 兩個Service的相互監(jiān)視實現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下
    2016-10-10
  • Android開發(fā)手冊RatingBar星級評分控件實例

    Android開發(fā)手冊RatingBar星級評分控件實例

    這篇文章主要為大家介紹了Android開發(fā)手冊RatingBar星級評分控件實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • Kotlin Job啟動流程源碼層深入分析

    Kotlin Job啟動流程源碼層深入分析

    如果要我拿現(xiàn)實中的一事物與Kotlin協(xié)程中的Job做一個類比,那么我會把Job比作成海洋中的冰山。自由漂浮的冰山約有90%體積沉在海水表面下,因此看著浮在水面上的形狀并猜不出水下的形狀
    2022-11-11

最新評論