最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Kotlin中l(wèi)et、run、with、apply及also的用法和差別

 更新時間:2023年11月28日 11:42:05   作者:郭霖  
作用域函數(shù)是Kotlin比較重要的一個特性,分為5種let、run、with、apply及also,這五個函數(shù)的工作方式非常相似,但是我們需要了解這5種函數(shù)的差異,以便在不同的場景更好的利用它,這篇文章主要介紹了Kotlin中l(wèi)et、run、with、apply及also的差別,需要的朋友可以參考下

前言   

作用域函數(shù)是Kotlin比較重要的一個特性,共分為以下5種:let、run、with、apply 以及 also,這五個函數(shù)的工作方式可以說非常相似,但是我們需要了解的是這5種函數(shù)的差異,以便在不同的場景更好的利用它。讀完這篇文章您將了解到:

  • 什么是Kotlin的作用域函數(shù)?

  • let、run、with、apply 以及 also這5種作用域函數(shù)各自的角色定位;

  • 5種作用域函數(shù)的差異區(qū)分;

  • 何時何地使用這5種作用域?

Kotlin的作用域函數(shù)

Kotlin 標(biāo)準(zhǔn)庫包含幾個函數(shù),它們的唯一目的是在對象的上下文中執(zhí)行代碼塊。當(dāng)對一個對象調(diào)用這樣的函數(shù)并提供一個 lambda 表達(dá)式時,它會形成一個臨時作用域。在此作用域中,可以訪問該對象而無需其名稱。這些函數(shù)稱為作用域函數(shù)。

簡單來說,作用域函數(shù)是為了方便對一個對象進(jìn)行訪問和操作,你可以對它進(jìn)行空檢查或者修改它的屬性或者直接返回它的值等操作,下面提供了案例對作用域函數(shù)進(jìn)行了詳細(xì)說明。

角色定位 

let

public inline fun <T, R> T.let(block: (T) -> R): R 

let函數(shù)是參數(shù)化類型 T 的擴(kuò)展函數(shù)。在let塊內(nèi)可以通過 it 指代該對象。返回值為let塊的最后一行或指定return表達(dá)式。

我們以一個Book對象為例,類中包含Book的name和price,如下:

class Book() {
    var name = "《數(shù)據(jù)結(jié)構(gòu)》"
    var price = 60
    fun displayInfo() = print("Book name : $name and price : $price")
}
fun main(args: Array<String>) {
    val book = Book().let {
        it.name = "《計(jì)算機(jī)網(wǎng)絡(luò)》"
        "This book is ${it.name}"
    }
    print(book)
}
控制臺輸出:
This book is 《計(jì)算機(jī)網(wǎng)絡(luò)》

在上面案例中,我們對Book對象使用let作用域函數(shù),在函數(shù)塊的最后一句添加了一行字符串代碼,并且對Book對象進(jìn)行打印,我們可以看到最后控制臺輸出的結(jié)果為字符串“This book is 《計(jì)算機(jī)網(wǎng)絡(luò)》”。

按照我們的編程思想,打印一個對象,輸出必定是對象,但是使用let函數(shù)后,輸出為最后一句字符串。這是由于let函數(shù)的特性導(dǎo)致。因?yàn)樵贙otlin中,如果let塊中的最后一條語句是非賦值語句,則默認(rèn)情況下它是返回語句。

那如果我們將let塊中最后一條語句修改為賦值語句,會發(fā)生什么變化?

fun main(args: Array<String>) {
    val book = Book().let {
        it.name = "《計(jì)算機(jī)網(wǎng)絡(luò)》"
    }
    print(book)
}
控制臺輸出:
kotlin.Unit

可以看到我們將Book對象的name值進(jìn)行了賦值操作,同樣對Book對象進(jìn)行打印,但是最后控制臺的輸出結(jié)果為“kotlin.Unit”,這是因?yàn)樵趌et函數(shù)塊的最后一句是賦值語句,print則將其當(dāng)做是一個函數(shù)來看待。

這是let角色設(shè)定的第一點(diǎn)

let塊中的最后一條語句如果是非賦值語句,則默認(rèn)情況下它是返回語句,反之,則返回的是一個Unit類型。

我們來看let的第二點(diǎn)

let可用于空安全檢查。

如需對非空對象執(zhí)行操作,可對其使用安全調(diào)用操作符 ?. 并調(diào)用let在lambda表達(dá)式中執(zhí)行操作。如下案例:

var name: String? = null
fun main(args: Array<String>) {
    val nameLength = name?.let {
        it.length
    } ?: "name為空時的值"
    print(nameLength)
}

我們設(shè)置name為一個可空字符串,利用name?.let來進(jìn)行空判斷,只有當(dāng)name不為空時,邏輯才能走進(jìn)let函數(shù)塊中。在這里,我們可能還看不出來let空判斷的優(yōu)勢,但是當(dāng)你有大量name的屬性需要編寫的時候,就能發(fā)現(xiàn)let的快速和簡潔。

let的第三點(diǎn)

let可對調(diào)用鏈的結(jié)果進(jìn)行操作。

關(guān)于這一點(diǎn),官方教程給出了一個案例,在這里就直接使用:

fun main(args: Array<String>) { 
    val numbers = mutableListOf("One","Two","Three","Four","Five")
    val resultsList = numbers.map { it.length }.filter { it > 3 }
    print(resultsList)
}

我們的目的是獲取數(shù)組列表中長度大于3的值。因?yàn)槲覀儽仨毚蛴〗Y(jié)果,所以我們將結(jié)果存儲在一個單獨(dú)的變量中,然后打印它。但是使用“let”操作符,我們可以將代碼修改為:

fun main(args: Array<String>) {
    val numbers = mutableListOf("One","Two","Three","Four","Five")
    numbers.map { it.length }.filter { it > 3 }.let {
        print(it)
    }
}

使用let后可以直接對數(shù)組列表中長度大于3的值進(jìn)行打印,去掉了變量賦值這一步。

另外,let函數(shù)還存在一個特點(diǎn)。

let的第四點(diǎn)

let可以將“It”重命名為一個可讀的lambda參數(shù)。

let是通過使用“It”關(guān)鍵字來引用對象的上下文,因此,這個“It”可以被重命名為一個可讀的lambda參數(shù),如下將it重命名為book:

fun main(args: Array<String>) {
    val book = Book().let {book ->
        book.name = "《計(jì)算機(jī)網(wǎng)絡(luò)》"
    }
    print(book)
}

run

run函數(shù)以“this”作為上下文對象,且它的調(diào)用方式與let一致。

另外,第一點(diǎn):當(dāng) lambda 表達(dá)式同時包含對象初始化和返回值的計(jì)算時,run更適合。

這句話是什么意思?我們還是用案例來說話:

fun main(args: Array<String>) {
    Book().run {
        name = "《計(jì)算機(jī)網(wǎng)絡(luò)》"
        price = 30
        displayInfo()
    }
}
控制臺輸出:
Book name : 《計(jì)算機(jī)網(wǎng)絡(luò)》 and price : 30

如果不使用run函數(shù),相同功能下代碼會怎樣?來看一看:

fun main(args: Array<String>) {
    val book = Book()
    book.name = "《計(jì)算機(jī)網(wǎng)絡(luò)》"
    book.price = 30
    book.displayInfo()
}
控制臺輸出:
Book name : 《計(jì)算機(jī)網(wǎng)絡(luò)》 and price : 30

輸出結(jié)果還是一樣,但是run函數(shù)所帶來的代碼簡潔程度已經(jīng)顯而易見。

除此之外,讓我們來看看run函數(shù)的其他優(yōu)點(diǎn)。通過查看源碼,了解到run函數(shù)存在兩種聲明方式。

1、與let一樣,run是作為T的擴(kuò)展函數(shù)。

inline fun <T, R> T.run(block: T.() -> R): R 

2、第二個run的聲明方式則不同,它不是擴(kuò)展函數(shù),并且塊中也沒有輸入值,因此,它不是用于傳遞對象并更改屬性的類型,而是可以使你在需要表達(dá)式的地方就可以執(zhí)行一個語句。

inline fun <R> run(block: () -> R): R

如下利用run函數(shù)塊執(zhí)行方法,而不是作為一個擴(kuò)展函數(shù)。

run {
        val book = Book()
        book.name = "《計(jì)算機(jī)網(wǎng)絡(luò)》"
        book.price = 30
        book.displayInfo()
    }

with

inline fun <T, R> with(receiver: T, block: T.() -> R): R 

with屬于非擴(kuò)展函數(shù),直接輸入一個對象receiver,當(dāng)輸入receiver后,便可以更改receiver的屬性,同時,它也與run做著同樣的事情。

還是提供一個案例說明:

fun main(args: Array<String>) {
    val book = Book()
    with(book) {
        name = "《計(jì)算機(jī)網(wǎng)絡(luò)》"
        price = 40
    }
    print(book)
}

以上面為例,with(T)類型傳入了一個參數(shù)book,則可以在with的代碼塊中訪問book的name和price屬性,并做更改。

with使用的是非null的對象,當(dāng)函數(shù)塊中不需要返回值時,可以使用with。

apply

inline fun <T> T.apply(block: T.() -> Unit): T
inline fun <T> T.apply(block: T.() -> Unit): T

apply是 T 的擴(kuò)展函數(shù),與run函數(shù)有些相似,它將對象的上下文引用為“this”而不是“it”,并且提供空安全檢查,不同的是,apply不接受函數(shù)塊中的返回值,返回的是自己的T類型對象。

fun main(args: Array<String>) {
    Book().apply {
        name = "《計(jì)算機(jī)網(wǎng)絡(luò)》"
        price = 40
    }
    print(book)
}
控制臺輸出:
com.fuusy.kotlintest.Book@61bbe9ba

前面看到的 let、with 和 run 函數(shù)返回的值都是 R。但是,apply 和下面查看的 also 返回 T。例如,在 let 中,沒有在函數(shù)塊中返回的值,最終會成為 Unit 類型,但在 apply 中,最后返回對象本身 (T) 時,它成為 Book 類型。

apply函數(shù)主要用于初始化或更改對象,因?yàn)樗糜谠诓皇褂脤ο蟮暮瘮?shù)的情況下返回自身。

also

inline fun <T> T.also(block: (T) -> Unit): T 

also是 T 的擴(kuò)展函數(shù),返回值與apply一致,直接返回T。also函數(shù)的用法類似于let函數(shù),將對象的上下文引用為“it”而不是“this”以及提供空安全檢查方面。

因?yàn)門作為block函數(shù)的輸入,可以使用also來訪問屬性。所以,在不使用或不改變對象屬性的情況下也使用also。

fun main(args: Array<String>) {
    val book  = Book().also {
        it.name = "《計(jì)算機(jī)網(wǎng)絡(luò)》"
        it.price = 40
    }
    print(book)
}
控制臺輸出:
com.fuusy.kotlintest.Book@61bbe9ba

差異化   

let & run

  • let將上下文對象引用為it ,而run引用為this;

  • run無法將“this”重命名為一個可讀的lambda參數(shù),而let可以將“it”重命名為一個可讀的lambda參數(shù)。在let多重嵌套時,就可以看到這個特點(diǎn)的優(yōu)勢所在。

with & run

with和run其實(shí)做的是同一種事情,對上下文對象都稱之為“this”,但是他們又存在著不同,我們來看看案例。

先使用with函數(shù):

fun main(args: Array<String>) {
    val book: Book? = null
    with(book){
        this?.name = "《計(jì)算機(jī)網(wǎng)絡(luò)》"
        this?.price = 40
    }
    print(book)
}

我們創(chuàng)建了一個可空對象book,利用with函數(shù)對book對象的屬性進(jìn)行了修改。代碼很直觀,那么我們接著將with替換為run,代碼更改為:

fun main(args: Array<String>) {
    val book: Book? = null
    book?.run{
        name = "《計(jì)算機(jī)網(wǎng)絡(luò)》"
        price = 40
    }
    print(book)
}

首先run函數(shù)的調(diào)用省略了this引用,在外層就進(jìn)行了空安全檢查,只有非空時才能進(jìn)入函數(shù)塊內(nèi)對book進(jìn)行操作。相比較with來說,run函數(shù)更加簡便,空安全檢查也沒有with那么頻繁。

apply & let

  • apply不接受函數(shù)塊中的返回值,返回的是自己的T類型對象,而let能返回。

  • apply上下文對象引用為“this”,let為“it”。

何時應(yīng)該使用它們

  • 用于初始化對象或更改對象屬性,可使用apply

  • 如果將數(shù)據(jù)指派給接收對象的屬性之前驗(yàn)證對象,可使用also

  • 如果將對象進(jìn)行空檢查并訪問或修改其屬性,可使用let

  • 如果是非null的對象并且當(dāng)函數(shù)塊中不需要返回值時,可使用with

  • 如果想要計(jì)算某個值,或者限制多個本地變量的范圍,則使用run

小結(jié)  

以上便是Kotlin作用域函數(shù)的作用以及使用場景,在Android實(shí)際開發(fā)中,5種函數(shù)使用的頻次非常高,在使用過程中發(fā)現(xiàn),當(dāng)代碼邏輯少的時候,作用域函數(shù)能帶給我們代碼的簡潔性可讀性,但是當(dāng)邏輯復(fù)雜時,使用不同的函數(shù),多次疊加都將降低可讀性。這就要我們?nèi)^(qū)分它們各自的特點(diǎn),以便在適合且復(fù)雜的場景下去使用它。

到此這篇關(guān)于Kotlin中l(wèi)et、run、with、apply及also的用法和差別的文章就介紹到這了,更多相關(guān)Kotlin中l(wèi)et、run、with、apply also內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • springboot項(xiàng)目中使用Swagger的簡單示例

    springboot項(xiàng)目中使用Swagger的簡單示例

    大趨勢下目前很多的項(xiàng)目都采用了前后端分離的方式進(jìn)行開發(fā),最近我接觸到的項(xiàng)目大多數(shù)都是采用了前后端分離的方式進(jìn)行開發(fā),下面這篇文章主要給大家介紹了關(guān)于springboot項(xiàng)目中使用Swagger的簡單示例,需要的朋友可以參考下
    2023-04-04
  • Java 根據(jù)某個 key 加鎖的實(shí)現(xiàn)方式

    Java 根據(jù)某個 key 加鎖的實(shí)現(xiàn)方式

    日常開發(fā)中,有時候需要根據(jù)某個 key 加鎖,確保多線程情況下,對該 key 的加鎖和解鎖之間的代碼串行執(zhí)行,這篇文章主要介紹了Java 根據(jù)某個 key 加鎖的實(shí)現(xiàn)方式,需要的朋友可以參考下
    2023-03-03
  • SpringBoot整合Minio實(shí)現(xiàn)上傳文件的完整步驟記錄

    SpringBoot整合Minio實(shí)現(xiàn)上傳文件的完整步驟記錄

    MinIO是一個基于Apache License v2.0開源協(xié)議的對象存儲服務(wù),它兼容亞馬遜S3云存儲服務(wù)接口,非常適合于存儲大容量非結(jié)構(gòu)化的數(shù)據(jù),下面這篇文章主要給大家介紹了關(guān)于SpringBoot整合Minio實(shí)現(xiàn)上傳文件的完整步驟,需要的朋友可以參考下
    2022-05-05
  • Java?根據(jù)XPATH批量替換XML節(jié)點(diǎn)中的值

    Java?根據(jù)XPATH批量替換XML節(jié)點(diǎn)中的值

    這篇文章主要介紹了Java根據(jù)XPATH批量替換XML節(jié)點(diǎn)中的值,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-09-09
  • 淺談Mybatis版本升級踩坑及背后原理分析

    淺談Mybatis版本升級踩坑及背后原理分析

    這篇文章主要介紹了淺談Mybatis版本升級踩坑及背后原理分析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • Java  解決死鎖的方法實(shí)例詳解

    Java 解決死鎖的方法實(shí)例詳解

    這篇文章主要介紹了java 多線程死鎖詳解及簡單實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • java關(guān)鍵字super的騷操作詳解

    java關(guān)鍵字super的騷操作詳解

    關(guān)鍵字super在Java中用于引用當(dāng)前類的父類(即超類)的構(gòu)造方法、訪問父類的成員變量和方法,它提供了一種方便的方式來處理繼承關(guān)系中的父類操作,下面我們就來看看它有哪些騷操作吧
    2023-09-09
  • Java如何對方法進(jìn)行調(diào)用詳解

    Java如何對方法進(jìn)行調(diào)用詳解

    今天給大家整理了Java如何對方法進(jìn)行調(diào)用,文中有非常詳細(xì)的介紹及代碼示例,對正在學(xué)習(xí)java的小伙伴們很有幫助,需要的朋友可以參考下
    2021-06-06
  • SpringBoot讀取配置的6種方式

    SpringBoot讀取配置的6種方式

    本文主要介紹了SpringBoot讀取配置的6種方式,主要包括使用默認(rèn)配置、使用application.properties文件、使用application.yml文件、使用@Value注解、使用Environment對象和使用ConfigurableEnvironment對象,感興趣的可以了解一下
    2023-08-08
  • 淺談JMeter engine啟動原理

    淺談JMeter engine啟動原理

    本文主要介紹jmeter在控制臺在點(diǎn)擊執(zhí)行之后底層所做的一些主要事情及內(nèi)容,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09

最新評論

永泰县| 甘泉县| 海伦市| 新宁县| 宁城县| 玉林市| 新野县| 礼泉县| 上饶县| 虞城县| 长岛县| 茌平县| 章丘市| 万州区| 龙门县| 饶平县| 赤峰市| 吉木萨尔县| 清镇市| 秦皇岛市| 长汀县| 波密县| 邵东县| 连平县| 枣强县| 行唐县| 会东县| 会同县| 海门市| 桃园市| 儋州市| 西乌珠穆沁旗| 阿尔山市| 丰原市| 西丰县| 剑河县| 阳信县| 兴安县| 塔城市| 曲阜市| 合阳县|