kotlin之帶接收者的函數字面量

在kotlin中,帶接受者的函數字面量這個使用的地方還是很多的,需要仔細理解總結一下

在java中,函數(在java了,把函數稱方法)是定義在類裏面的,在調用函數的時候,都是先new一個類對象,然後,通過.調用函數。其實調用方法的過程,是把類對象傳給了方法,這個也是java常說的一個概念,就是方法有個默認參數是類對象。

在Kotlin中,由於函數是first class(一等公民),類的地位被弱化了,所以好多設計都是圍繞函數來的(函數式編程),java是面向對象編程的語言。接受者可以類比於java的類,也是用.操作符的,在實際使用的時候,也是用對象調用方法的,在函數體中,this也是表示調用方法的對象,我理解其實也是給方法傳入了一個類對象。把kotlin的這種函數定義叫“擴展函數”

先看一個簡單的帶接收者的lambda表達式的例子

    var subtract : Int.(Int) -> Int = {this - it}
    println(3.subtract(2))

這個很好理解,帶接收者的lambda表達式也是可以作爲函數參數的,這個需要理解一下,我們看看kotlin標準庫裏面的run方法

/**
 * Calls the specified function [block] with `this` value as its receiver and returns its result.
 *
 * For detailed usage information see the documentation for [scope functions](https://kotlinlang.org/docs/reference/scope-functions.html#run).
 */
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

首先run函數(方法),它自身是帶接收者的,接收者類型是T,T是一個範型,就理解成一個具體的類型就行。在run函數的函數體內,我們知道this可以操作這個接收者的,看第一個例子就明白了。然後我們看看run的參數,參數是個函數類型的,不過這裏是帶接收者的,也就是說在run函數體內是這樣使用的:

T類型的接收者實例.block()

在run方法內,this就是一個T類型的接收者實例,this可以省略,所以我們看到是block()這樣的調用,這樣,block具體代表的函數,其函數體內的this,就是調用run的T類型的接收者實例

好啦,具體細節分析完了,我們抽象出來看,就是:傳給run一個函數,函數體內可以訪問調用run的實例。看一個例子

        val mTvBtn = findViewById<TextView>(R.id.text)
        mTvBtn.run{
            text = "kotlin"
            textSize = 13f
        }

這樣的代碼一看就很簡潔呀,也知道這是要幹嘛,這個就是給TextView的屬性賦值

說明一下:run方法的參數是 () -> R類型的,這個意思就是這個函數沒有參數,返回類型是R類型。對有沒有參數的函數,lambda表達式中->和->前面的都可以省略掉。而且看這個意思,沒有指定具體R類型,說明也是沒有的,是沒有返回值的。所以我們纔看到有上面的代碼樣子

kotlin的標準庫裏還提供了不帶接收者的run方法,我們也看一下

/**
 * Calls the specified function [block] and returns its result.
 *
 * For detailed usage information see the documentation for [scope functions](https://kotlinlang.org/docs/reference/scope-functions.html#run).
 */
@kotlin.internal.InlineOnly
public inline fun <R> run(block: () -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}
package com.lzy.learnpro

import android.app.Activity
import android.os.Bundle
import android.widget.TextView

/**
 * @Author  zhongyili
 * @Date 2020/4/7
 */
class SecondActivity: Activity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val mTvBtn = findViewById<TextView>(R.id.text)

        mTvBtn.run{
            text = "kotlin"
            textSize = 13f
            //這個this是mTvBtn
            println(this)
        }

        //這個run方法相當於kotlin類的靜態方法
        kotlin.run {
            mTvBtn.text = "kotlin"
            mTvBtn.textSize = 13f
            //這個this是SecondActivity
            println(this)
        }

        //這個run的接收者是this,也就是SecondActivity,只是省略掉了
        run {
            mTvBtn.text = "kotlin"
            mTvBtn.textSize = 13f
            //這個this是SecondActivity
            println(this)
        }



    }
}

 

 

帶接收者的函數字面值與解構聲明詳解

Kotlin——高級篇(二):高階函數詳解與標準的高階函數使用

Kotlin與Java:this關鍵字

第八章 Kotlin之This,inner關鍵字

Kotlin的inline內聯函數

簡單理解 Kotlin 中的 inline 關鍵字

 

 

 

 

 


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章