kotlin中Scope函數(shù)

Scope函數(shù)翻譯過來就叫作用域函數(shù)吧闻坚,Kotlin中的作用域函數(shù)包含let, run with, apply, also五個(gè).
作用域函數(shù)方便我們更加容易操作對(duì)象本身舀患,使得代碼更加易讀求厕。舉個(gè)例子
定一個(gè)Person類

class Person(var name : String, var age : Int, var country : String) {
    override fun toString(): String {
        return "Person(name='$name', age=$age, city='$country')"
    }
}

通常操作如下

val person = Person("jay",22,"china")
person.country = "usa"
Log.i("tag", person.toString())

無非是更改國家后再輸出該對(duì)象的值柬唯,如果使用作用域中函數(shù)效果是

Person("jay",22,"china").let {
                it.country = "usa"
                Log.i("tag", it.toString())
            }

上面使用作用域函數(shù)代碼會(huì)更加清晰.
下面來說下每個(gè)作用域函數(shù)的區(qū)別. 主要有兩個(gè)

1债朵,引用到的context對(duì)象不同

2畸陡,返回值不同

下面分別來看

1,引用到的context對(duì)象不同

context有兩種架忌,一個(gè)是this一個(gè)是it.

fun main() {
    val str = "Hello"
    // this
    str.run {
        println("The receiver string length: $length")
        //println("The receiver string length: ${this.length}") // does the same
    }

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

run, with, apply是使用的是this作為context對(duì)象吞彤,因此在函數(shù)中,對(duì)象本身可以像它類中方法一樣使用叹放,你也可以忽略掉this的調(diào)用

val adam = Person("Adam").apply { 
    age = 20                       // same as this.age = 20 or adam.age = 20
    city = "London"
}
println(adam)

let和also以lambda參數(shù)形式傳入饰恕,它的context是it(前提是沒有指定參數(shù)名字).

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

val i = getRandomInt()

另外也可以自定義參數(shù)名字

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

val i = getRandomInt()
2,返回值不同

apply和also返回的context對(duì)象
let,run和with返回的是lambda執(zhí)行的結(jié)果
來看看also調(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()

在返回context對(duì)象這種情況下可以作為一個(gè)鏈?zhǔn)秸{(diào)用使用.
當(dāng)然也可以不去操作context對(duì)象井仰,用來輸出一些信息然后返回context對(duì)象

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

val i = getRandomInt()

另外一種情況就是let,run和with返回的是lambda執(zhí)行的結(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.")

每個(gè)作用域函數(shù)的區(qū)別

每個(gè)作用域函數(shù)實(shí)際上在使用上是可以互換的,主要是看如何使用起來更加方便易讀.

let

1,let用來在一個(gè)調(diào)用鏈返回后調(diào)用一個(gè)或者更多函數(shù)俱恶,舉個(gè)例子

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

如果使用write你可以重寫成

val numbers = mutableListOf("one", "two", "three", "four", "five")
numbers.map { it.length }.filter { it > 3 }.let { 
    println(it)
    // and more function calls if needed
} 

2,let用來執(zhí)行一個(gè)非空對(duì)象的代碼塊.

val str: String? = "Hello"   
//processNonNullString(str)       // compilation error: str can be null
val length = str?.let { 
    println("let() called on $it")        
    processNonNullString(it)      // OK: 'it' is not null inside '?.let { }'
    it.length
}

3,另外一個(gè)場景是let引進(jìn)一個(gè)本地變量去提高代碼的可讀性.

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

With通常需要穿一個(gè)context對(duì)象作為參數(shù)雹嗦,在函數(shù)內(nèi)部使用this作為context對(duì)象調(diào)用,返回值是lambda的執(zhí)行結(jié)果.
1, 通常我們用它做一些伴生操作合是,官方文檔認(rèn)為它 “with this object, do the following.” 自行體會(huì)

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

2了罪,另外可以用來計(jì)算一個(gè)結(jié)果后返回值

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

run屬于context對(duì)象是this, 返回結(jié)果是lambda執(zhí)行的結(jié)果.
1,通常用來執(zhí)行一些對(duì)象初始化和一些操作后返回結(jié)果, 它可以和let進(jìn)行互換

val service = MultiportService("https://example.kotlinlang.org", 80)

val result = service.run {
    port = 8080
    query(prepareRequest() + " to port $port")
}

// the same code written with let() function:
val letResult = service.let {
    it.port = 8080
    it.query(it.prepareRequest() + " to port ${it.port}")
}

2, run還有另外一個(gè)特點(diǎn),它可以不作為對(duì)象的擴(kuò)展函數(shù)聪全,直接調(diào)用執(zhí)行一個(gè)代碼塊.

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

apply的context是this, 返回對(duì)象的對(duì)象自己.
使用apply通常是對(duì)象的屬性進(jìn)行賦值操作,然后返回它自己泊藕,進(jìn)行一些鏈?zhǔn)讲僮?/p>

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

Context對(duì)象是it, 返回值是對(duì)象本身
通常用來做些輸出日志,打印調(diào)試信息的操作难礼,可以理解成and also do the following.

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

對(duì)于上面的描述娃圆,官方文檔給出了一張表格


image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末汽久,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子踊餐,更是在濱河造成了極大的恐慌景醇,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吝岭,死亡現(xiàn)場離奇詭異三痰,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)窜管,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門散劫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人幕帆,你說我怎么就攤上這事获搏。” “怎么了失乾?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵常熙,是天一觀的道長。 經(jīng)常有香客問我碱茁,道長裸卫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任纽竣,我火速辦了婚禮墓贿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蜓氨。我一直安慰自己聋袋,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布穴吹。 她就那樣靜靜地躺著幽勒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪刀荒。 梳的紋絲不亂的頭發(fā)上代嗤,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音缠借,去河邊找鬼。 笑死宜猜,一個(gè)胖子當(dāng)著我的面吹牛泼返,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播姨拥,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼绅喉,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼渠鸽!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起柴罐,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤徽缚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后革屠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凿试,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年似芝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了那婉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡党瓮,死狀恐怖详炬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情寞奸,我是刑警寧澤呛谜,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站枪萄,受9級(jí)特大地震影響呻率,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜呻引,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一礼仗、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧逻悠,春花似錦元践、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至饥伊,卻和暖如春象浑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背琅豆。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來泰國打工愉豺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人茫因。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓蚪拦,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子驰贷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容