天天看點

Kotlin-13-作用域函數

目錄

1、定義

2、作用

3、函數:run

4、函數:let

5、函數:apply

5、函數:also

6、函數:takeIf

7、函數:takeUnless

8、函數:with

9、總結

1、定義

對象的擴充函數。

如下圖:1、紅色框内的就是pig對象所能調用的擴充函數(這些擴充函數對所有對象都适用)

               2、綠色框内就是run擴充函數的源碼,具體講解這個擴充函數的作用

Kotlin-13-作用域函數

2、作用

可以在這些擴充函數中,對該對象進行進一步的處理。

3、函數:run

它的作用就是将這個函數所得到的值進行傳回。
  • 注意:run函數隻能傳回它的最後一條語句的所得到的值,如下:result2傳回的是第二條語句 this.name + "長胖了" 的值。
  • 解決:如果你想要傳回第一條語句的值,可以使用[email protected]方法進行傳回。
fun main() {

    val pig = Pig("花姑娘", 300)

    val result1 = pig.run {
        this.name + "長胖了"
    }


    val result2 = pig.run {
        this.name + "長胖了"
        this.weight + 30
    }

    val result3 = pig.run {
        [email protected] this.name + "長胖了"
        this.weight + 20
    }

    println("result1=$result1")
    println("result2=$result2")
    println("result3=$result3")
}
//輸出結果
result1=花姑娘長胖了
result2=330
result3=花姑娘長胖了
           

4、函數:let

它的作用和run函數一樣都是對函數所得到的值進行傳回。
  1. 唯一不同:它需要将調用let函數的對象本身,傳入到Lambda閉包函數的參數中。
  2. 當然我們可以對這個參數進行簡寫(Lambda隻有一個參數的話,可以省略),省略之後,如果想要調用自身對象的屬性可以使用it

如下:let的閉包函數的參數pig1其實就是pig本身。

val pig = Pig("花姑娘", 300)
 
  val newName = pig.let { pig1: Pig ->
        pig1.name + "瘦了"
    }

  val newName1 = pig.let {
        it.name + "瘦了"
    }

  println("newName=$newName")
  println("newName1=$newName1")

//輸出結果
newName=花姑娘瘦了
newName1=花姑娘瘦了
           

我們可以簡單可一下它的源碼。這裡的let是一個範型方法,T代表對象本身,R代表Lambda閉包函數。

block:(T)-> R  可以看到在lambda函數中的參數就是對象本身T,

return block(this)  代表傳回lambda函數的運作結果,

至于中間的 contract 它其實就是一個契約函數,後面我們進行詳細講述。

/**
 * Calls the specified function [block] with `this` value as its argument and returns its result.
 */
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block(this)
}
           

5、函數:apply

它的傳回對象是對象本身,是以我們可以用它對自身屬性進行一些操作,再傳回本身。(類似于集合的一些操作符)

 後面我附上了源碼,可以看到return this,這個this,就是對象本身。

data class Chicken(var name: String, var weight: Int)

fun main() {

    val chicken = Chicken("小母雞", 30)

    val chickenNew = chicken.apply {
        println("原來的名字:${this.name}")
        this.name = "小花雞"
    }

    println("現在的名字:${chickenNew.name}")
}

//輸出結果
原來的名字:小母雞
現在的名字:小花雞

           

5、函數:also

源碼:
/**
 * Calls the specified function [block] with `this` value as its receiver and returns `this` value.
 */
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}
           

它的作用和apply一樣,都是傳回自己,我們在這裡可以對對象本身進行操作, 然後再傳回。

差別:also需要将對象本身作為參數傳入到lambda函數的參數中,這個差別和run、let的差別一樣。

data class Chicken(var name: String, var weight: Int)

fun main() {

    val chicken = Chicken("小母雞", 30)

    val chickenAlso = chicken.also { chicken1: Chicken ->
        println("原來的重量:${chicken1.weight}")
        chicken1.weight = 40
    }
    
    println("現在的重量:${chickenAlso.weight}")
}
//輸出結果
原來的重量:30
現在的重量:40

源碼:
/**
 * Calls the specified function [block] with `this` value as its argument and returns `this` value.
 */
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.also(block: (T) -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block(this)
    return this
}
           

6、函數:takeIf

//源碼:
/**
 * Returns `this` value if it satisfies the given [predicate] or `null`, if it doesn't.
 */
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? {
    contract {
        callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
    }
    return if (predicate(this)) this else null
}
           

從源碼可以看出,它最後傳回的是根據Lambda閉包函數predicate的boolean值來決定的。

如果是true就傳回對象本身,

如果是false就傳回null。

  • 作用:這個函數的作用的話,我們可以在takeif裡邊對對象本身的屬性進行判斷,如果符合條件就輸出,否則就傳回null。
  • 注意1:在takeif裡邊最後一條語句必須是判斷語句,否則就會報錯。
  • 注意2:如果有多條判斷語句,我們可以根據[email protected]  來決定傳回那條語句的boolean值。
data class Cat(var name: String, var weight: Int)

fun main() {

    val cat=Cat("小花",10)

    val cat1=cat.takeIf {catP: Cat ->
        catP.weight>10
    }
    val cat2 =cat.takeIf {catP: Cat ->
        catP.weight<=10
    }
    val cat3=cat.takeIf {catP: Cat ->
        [email protected] catP.weight>10
        catP.weight<10
        //1+1//報錯
    }

    println("cat1=$cat1")
    println("cat2=$cat2")
    println("cat3=$cat3")

}
//輸出結果
cat1=null
cat2=Cat(name=小花, weight=10)
cat3=null
           

7、函數:takeUnless

它的作用和takeif一樣,不同的是它根據閉包函數predicate的boolean值傳回的結果相反。

如果是true傳回null,

如果是false傳回對象本身。

data class Cat(var name: String, var weight: Int)

fun main() {

    val cat = Cat("小花", 10)

    val cat1 = cat.takeIf { catP: Cat ->
        catP.weight > 10
    }
    val cat12 = cat.takeUnless {
        it.weight > 10
    }

    println("cat1=$cat1")
    println("cat12=$cat12")
}
//輸出結果
cat1=null
cat12=Cat(name=小花, weight=10)
           

8、函數:with

//源碼
/**
 * Calls the specified function [block] with the given [receiver] as its receiver and returns its result.
 */
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return receiver.block()
}
           

從源碼我們看到它不需要對象來調用它,它其實是一個頂級函數,也就shi你在哪裡都可以調用這個函數。

但是它需要兩個參數,一個是一個對象receiver,另一個是閉包函數block

它的傳回值就是參數對象receiver對閉包函數block的調用結果

  • 可見它的作用可以有很多,比對一個對象進行屬性的修改,或這對一個view進行一系列操作,它看起來可以讓代碼實作了子產品化。
data class Cat(var name: String, var weight: Int)

fun main() {

    val cat = Cat("小花", 10)

    val result=with(cat){
        this.name="小白"
        this.weight=11
        1+1
    }

    println("cat.name=${cat.name}")
    println("cat.weight=${cat.weight}")
    println("result=$result")    
}

//輸出結果
cat.name=小白
cat.weight=11
result=2
           

9、總結

這些作用域函數的作用還是具有很多的開放性,你可以用他們來做很多邏輯指派操作。這就要看你的發揮了。
data class Cat(var name: String, var weight: Int)

fun main() {

    val cat = Cat("小花", 10)

    val newName = cat.also {
        it.name = it.name + "+1"
    }.takeIf {
        it.weight <= 10
    }?.apply {
        this.name = this.name + "+2"
    }?.run {
        [email protected] name + "+3"
    }

    println("newName=$newName")

}
//輸出結果

newName=小花+1+2+3