日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Kotlin-Learning 扩展

發布時間:2025/6/15 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Kotlin-Learning 扩展 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

與 C#,Gosu 類似。kotlin 可以不繼承父類,也不使用裝飾器模式對原有的類進行擴展,添加新的功能。

Kotlin 支持函數擴展和屬性擴展

擴展函數

package classandobject// MutableList<Int> 作為 swap 函數的接收者。 // 交換兩個下標的位置 fun MutableList<Int>.swap(index1: Int, index2: Int) {val temp = this[index1]this[index1] = this[index2]this[index2] = temp } 復制代碼

擴展函數的前綴是這個函數的接收者。 上面的擴展函數給 MutableList 添加了一個新功能 swap, 交換 2 個數的位置。

擴展是被靜態解析的

擴展沒有修改它所擴展的類,定義一個擴展,并沒有插入一個新的成員。只是能讓這個類的實例通過 . 調用擴展函數。

擴展函數是靜態分發的。

舉個例子:

open class Cclass D:C()fun C.foo() = "c" fun D.foo() = "d"fun printFoo(c:C){println(c.foo()) }輸出:c 復制代碼

雖然傳進了 D 的實例作為參數,foo 并不是 D 的一個成員函數,和 D 沒關系。這里由聲明參數的類型決定調用誰的方法,這里聲明了 C 類型,就會調用 C 的 foo()。

同名的成員函數優先級大于擴展函數:

class E {fun foo() {println("member")} }fun E.foo() {println("extension") } // 輸出 member 復制代碼

接收者為空的情況

fun Any?.toString(): String {if (this == null) {return "null"}return toString() } 復制代碼

要擴展的類可能為 null。可以對其做 null 的判斷處理。

擴展屬性

// 屬性擴展, 必須定義訪問器 val <T> List<T>.lastIndex: Intget() = size - 1復制代碼

擴展屬性不會真正給類添加一個屬性,沒法讓這個屬性有一個 backing field,所以不可以初始化。只能通過 set,get 定義。

伴隨對象擴展

如果一個類定義了伴隨對象,也可以為這個伴隨對象定義擴展函數和擴展屬性。

// 為伴隨對象定義擴展函數和擴展屬性 class CompanionClass{companion object{// ...} }fun CompanionClass.Companion.foo(){println("CompanionClass.Companion.foo()") } 復制代碼

使用 類名.方法() 直接調用:

CompanionClass.foo() 復制代碼

擴展的范圍

大部分都是用在包名下。

package foo.barfun Baz.goo() { ... } 復制代碼

用在別的包名下,需要導包 import

將擴展作為成員聲明

class D1 {fun bar(){//...println("D1.bar()")} }// 在 C1 類聲明 D1 類的擴展函數 foo() class C1 {private fun baz(){println("C1.baz()")}fun D1.foo(){bar() // calls D1.barbaz() // call C1.baz}fun caller(d:D1){d.foo()} } 復制代碼

將 D1 的擴展函數作為成員聲明在 C1 中。此時 D1 叫 extension receiver.C1 負責分發,叫 dispatch receiver。

在 C1 中的 foo() 擴展函數既可以調用 D1 中的函數,也可以調用 C1 中的函數,如果同名的話,優先調用 D1 中的。 同名的屬性也是一樣。

為了調用 C1 中的同名函數,可以用 this 限定符。

class C {fun D.foo() {toString() // calls D.toString()this@C.toString() // calls C.toString()} 復制代碼

dispath receiver 類型是動態的

定義在類中的擴展函數可以被子類重寫。

// receiver type 是靜態的。 dispatch receiver type 是動態的 open class Rclass R1 : R()open class T {open fun R.foo() {println("R.foo in T")}open fun R1.foo() {println("R1.foo in T")}fun caller(r: R) {r.foo()} }class T1 : T() {override fun R.foo() {println("R.foo in T1")}override fun R1.foo() {println("R1.foo in T1")} }// 調用 T().caller(R()) T().caller(R1())T1().caller(R()) T1().caller(R1())// 輸出 R.foo in T R.foo in T R.foo in T1 R.foo in T1 復制代碼

前面也提到擴展函數動動態解析的。由于 caller 中參數定義了類型為 R 所以只會調用 R 的擴展函數。而分發者的類型是動態的。

為什么要有擴展函數

在 java 中我們會在一個類中寫很多靜態方法作為工具類。FileUtils,StringUtils...

在 Java 代碼中。有時候在一句代碼中需要使用一個工具類的多個方法,就會變成這樣:

Collections.swap(list, Collections.binarySearch(list, Collections.max(otherList)), Collections.max(list)); 復制代碼

可以使用靜態導包(static import)的方式解決:

swap(list, binarySearch(list, max(otherList)), max(list)); 復制代碼

list 看起來重復。

這樣寫更簡潔,把所有的方法都歸納到 list 內當中,就不需要每個地方都傳一個 list 對象。

list.swap(list.binarySearch(otherList.max()), list.max()); 復制代碼

但是不可能在 List 中實現所有的方法。但是 Kotlin 的擴展可以做到,這就是為什么需要擴展的原因。

《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的Kotlin-Learning 扩展的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。