中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Kotlin1.6.20新功能Context?Receivers怎么使用

發布時間:2022-06-23 09:25:05 來源:億速云 閱讀:304 作者:iii 欄目:開發技術

本篇內容介紹了“Kotlin1.6.20新功能Context Receivers怎么使用”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

擴展函數的局限性

在 Kotlin 中接受者只能應用在擴展函數或者帶接受者 lambda 表達式中, 如下所示。

class Context {
    var density = 0f
}
// 擴展函數
inline fun Context.px2dp(value: Int): Float = value.toFloat() / density

接受者是 fun 關鍵字之后點之前的類型 Context,這里隱藏了兩個知識點。

  • 我們可以像調用內部函數一樣,調用擴展函數 px2dp(),通常結合 Kotlin 作用域函數 with , run , apply 等等一起使用。

with(Context()) {
    px2dp(100)
}
  • 在擴展函數內部,我們可以使用 this 關鍵字,或者隱藏關鍵字隱式訪問內部的成員函數,但是我們不能訪問私有成員

擴展函數使用起來很方便,我們可以對系統或者第三方庫進行擴展,但是也有局限性。

  • 只能定義一個接受者,因此限制了它的可組合性,如果有多個接受者只能當做參數傳遞。比如我們調用 px2dp() 方法的同時,往 logcat 和 file 中寫入日志。

class LogContext {
    fun logcat(message: Any){}
}
class FileContext {
    fun writeFile(message: Any) {}
}
fun printf(logContext: LogContext, fileContext: FileContext) {
    with(Context()) {
        val dp = px2dp(100)
        logContext.logcat("print ${dp} in logcat")
        fileContext.writeFile("write ${dp} in file")
    }
}
  • 在 Kotlin 中接受者只能應用在擴展函數或者帶接受者 lambda 表達式中,卻不能在普通函數中使用,失去了靈活性

Context Receivers 的出現帶來新的可能性,它通過了組合的方式,將多個上下文接受者合并在一起,靈活性更高,應用范圍更廣。

什么是 Context Receivers

Context Receivers 用于表示一個基本約束,即在某些情況下需要在某些范圍內才能完成的事情,它更加的靈活,可以通過組合的方式,組織上下文,將系統或者第三方類組合在一起,實現更多的功能。

如果想在項目中使用 Context Receivers,需要將 Kotlin 插件升級到 1.6.20 ,并且在項目中開啟才可以使用。

plugins {
    id 'org.jetbrains.kotlin.jvm' version '1.6.20'
}
// ......
kotlinOptions {
    freeCompilerArgs = ["-Xcontext-receivers"]
}

如何使用 Context Receivers

當我們完成上述配置之后,就可以在項目中使用 Context Receivers,現在我們將上面的案例改造一下。

context(LogContext, FileContext)
fun printf() {
    with(Context()) {
        val dp = px2dp(100)
        logContext.logcat("print ${dp} in logcat")
        fileContext.writeFile("write ${dp} in file")
    }
}

我們在 printf() 函數上,使用 context() 關鍵字,在 context() 關鍵字括號中,聲明上下文接收者類型的列表,多個類型用逗號分隔。但是列出的類型不允許重復,它們之間不允許有子類型關系。

通過 context() 關鍵字來限制它的作用范圍,在這個函數中,我們可以調用上下文 LogContext 、 FileContext 內部的方法,但是使用的時候,只能通過 Kotlin 作用域函數嵌套來傳遞多個接受者,也許在未來可能會提供更加優雅的方式。

with(LogContext()) {
    with(FileContext()) {
        printf("I am DHL")
    }
}

引入 Context Receivers 導致可讀性問題

如果我們在 LogContext 和 FileContext 中聲明了多個相同名字的變量或者函數,我們只能通過 this@Lable 語句來解決這個問題。

context(LogContext, FileContext)
fun printf(message: String) {
    logcat("print message in logcat ${this@LogContext.name}")
    writeFile("write message in file ${this@FileContext.name}")
}

正如你所見,在 LogContext 和 FileContext 中都有一個名為 name 的變量,我們只能通過 this@Lable 語句來訪問,但是這樣會引入一個新的問題,如果有大量的同名的變量或者函數,會導致 this 關鍵字分散到處都是,造成可讀性很差。所以我們可以通過接口隔離的方式,來解決這個問題。

interface LogContextInterface{
    val logContext:LogContext
}
interface FileContextInterface{
    val fileContext:FileContext
}
context(LogContextInterface, FileContextInterface)
fun printf(message: String) {
    logContext.logcat("print message in logcat ${logContext.name}")
    fileContext.writeFile("write message in file ${fileContext.name}")
}

通過接口隔離的方式,我們就可以解決 this 關鍵字導致的可讀性差的問題,使用的時候需要實例化接口。

val logContext = object : LogContextInterface {
    override val logContext: LogContext = LogContext()
}
val fileContext = object : FileContextInterface {
    override val fileContext: FileContext = FileContext()
}
with(logContext) {
    with(fileContext) {
        printf("I am DHL")
    }
}

Context Receivers 應用范圍及注意事項

當我們重寫帶有上下文接受者的函數時,必須聲明為相同類型的上下文接受者。

interface Canvas
interface Shape {
    context(Canvas)
    fun draw()
}
class Circle : Shape {
    context(Canvas)
    override fun draw() {
    }
}

我們重寫了 draw() 函數,聲明的上下文接受者必須是相同的,Context Receivers 不僅可以作用在擴展函數、普通函數上,而且還可以作用在類上。

context(LogContextInterface, FileContextInterface)
class LogHelp{
    fun printf(message: String) {
        logContext.logcat("print message in logcat ${logContext.name}")
        fileContext.writeFile("write message in file ${fileContext.name}")
    }
}

在類 LogHelp 上使用了 context() 關鍵字,我們就可以在 LogHelp 范圍內任意的地方使用 LogContext 或者 FileContex。

val logHelp = with(logContext) {
    with(fileContext) {
        LogHelp()
    }
}
logHelp.printf("I am DHL")

Context Receivers 除了作用在擴展函數、普通函數、類上,還可以作用在屬性 getter 和 setter 以及 lambda 表達式上。

context(View)
val Int.dp get() = this.toFloat().dp
// lambda 表達式
fun save(block: context(LogContextInterface) () -> Unit) {
}

最后我們來看一下,來自社區 Context Receivers 實踐的案例,擴展 Json 工具類。

fun json(build: JSONObject.() -> Unit) = JSONObject().apply { build() }
context(JSONObject)
infix fun String.by(build: JSONObject.() -> Unit) = put(this, JSONObject().build())
context(JSONObject)
infix fun String.by(value: Any) = put(this, value)
fun main() {
    val json = json {
        "name" by "Kotlin"
        "age" by 10
        "creator" by {
            "name" by "JetBrains"
            "age" by "21"
        }
    }
}

“Kotlin1.6.20新功能Context Receivers怎么使用”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

罗山县| 陆良县| 贡觉县| 建宁县| 绵阳市| 沁源县| 开鲁县| 天峻县| 隆林| 龙陵县| 株洲县| 东乌| 长顺县| 日照市| 武邑县| 丹寨县| 卢龙县| 黎川县| 三原县| 佛山市| 吐鲁番市| 陆丰市| 井陉县| 尉氏县| 湘西| 五台县| 垦利县| 衡阳县| 涟源市| 资阳市| 沐川县| 加查县| 宁远县| 林西县| 普兰店市| 于都县| 闻喜县| 太保市| 五指山市| 彝良县| 万州区|