亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

角色定位 

let

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

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

我們以一個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 = "《計算機網(wǎng)絡》"
        "This book is ${it.name}"
    }
    print(book)
}
控制臺輸出:
This book is 《計算機網(wǎng)絡》

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

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

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

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

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

這是let角色設定的第一點

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

我們來看let的第二點

let可用于空安全檢查。

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

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

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

let的第三點

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

關(guā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的值。因為我們必須打印結(jié)果,所以我們將結(jié)果存儲在一個單獨的變量中,然后打印它。但是使用“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的值進行打印,去掉了變量賦值這一步。

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

let的第四點

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 = "《計算機網(wǎng)絡》"
    }
    print(book)
}

run

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

另外,第一點:當 lambda 表達式同時包含對象初始化和返回值的計算時,run更適合。

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

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

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

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

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

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

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

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

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

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

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

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

with

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

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

還是提供一個案例說明:

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

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

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

apply

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

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

fun main(args: Array<String>) {
    Book().apply {
        name = "《計算機網(wǎng)絡》"
        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ù)主要用于初始化或更改對象,因為它用于在不使用對象的函數(shù)的情況下返回自身。

also

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

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

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

fun main(args: Array<String>) {
    val book  = Book().also {
        it.name = "《計算機網(wǎng)絡》"
        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多重嵌套時,就可以看到這個特點的優(yōu)勢所在。

with & run

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

先使用with函數(shù):

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

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

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

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

apply & let

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

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

何時應該使用它們

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

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

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

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

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

小結(jié)  

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

到此這篇關(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)文章

  • Java RPC框架過濾器機制原理解析

    Java RPC框架過濾器機制原理解析

    這篇文章主要介紹了Java RPC框架過濾器機制原理解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-02-02
  • Springboot內(nèi)嵌SQLite配置使用詳解

    Springboot內(nèi)嵌SQLite配置使用詳解

    這篇文章主要介紹了Springboot內(nèi)嵌SQLite配置使用詳解,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-08-08
  • spring.datasource.schema配置詳解

    spring.datasource.schema配置詳解

    本文主要介紹了spring.datasource.schema配置,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • Springboot中使用Redisson+AOP+自定義注解實現(xiàn)訪問限流與黑名單攔截

    Springboot中使用Redisson+AOP+自定義注解實現(xiàn)訪問限流與黑名單攔截

    本文主要介紹了Springboot中使用Redisson+AOP+自定義注解實現(xiàn)訪問限流與黑名單攔截,包含針對用戶IP限流,整個接口的訪問限流,以及對某個參數(shù)字段的限流,并且支持請求限流后處理回調(diào),感興趣的可以了解一下
    2024-02-02
  • Java設計模式之策略模式示例詳解

    Java設計模式之策略模式示例詳解

    策略模式屬于Java?23種設計模式中行為模式之一,該模式定義了一系列算法,并將每個算法封裝起來,使它們可以相互替換,且算法的變化不會影響使用算法的客戶。本文將通過示例詳細講解這一模式,需要的可以參考一下
    2022-03-03
  • 詳談ServiceLoader實現(xiàn)原理

    詳談ServiceLoader實現(xiàn)原理

    下面小編就為大家?guī)硪黄斦凷erviceLoader實現(xiàn)原理。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-02-02
  • java根據(jù)當前時間獲取yyyy-MM-dd?HH:mm:ss標準格式的時間代碼示例

    java根據(jù)當前時間獲取yyyy-MM-dd?HH:mm:ss標準格式的時間代碼示例

    在Java中可以使用java.time包中的LocalDateTime類和DateTimeFormatter類來獲取并格式化當前時間為yyyy-MM-dd?HH:mm:ss的格式,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-10-10
  • Gradle進階使用結(jié)合Sonarqube進行代碼審查的方法

    Gradle進階使用結(jié)合Sonarqube進行代碼審查的方法

    今天小編就為大家分享一篇關(guān)于Gradle進階使用結(jié)合Sonarqube進行代碼審查的方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • 解決SpringMVC @RequestMapping不設置value出現(xiàn)的問題

    解決SpringMVC @RequestMapping不設置value出現(xiàn)的問題

    這篇文章主要介紹了解決SpringMVC @RequestMapping不設置value出現(xiàn)的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java實現(xiàn)克隆的三種方式實例總結(jié)

    Java實現(xiàn)克隆的三種方式實例總結(jié)

    這篇文章主要介紹了Java實現(xiàn)克隆的三種方式,結(jié)合實例形式總結(jié)分析了java淺復制、深復制以及使用serializable實現(xiàn)深復制的相關(guān)操作技巧,需要的朋友可以參考下
    2018-08-08

最新評論