Skip to content

中級:擴展函數

在本章中,您將探索特殊的 Kotlin 函數,它們能讓您的程式碼更簡潔、更易讀。了解它們如何幫助您使用高效的設計模式,將您的專案提升到新的水平。

擴展函數

在軟體開發中,您經常需要在不更改原始程式碼的情況下修改程式的行為。例如,在您的專案中,您可能希望為來自第三方函式庫的類別添加額外功能。

擴展函數允許您為類別擴展額外功能。您呼叫擴展函數的方式與呼叫類別的成員函數相同,使用一個句點 .

在介紹擴展函數的完整語法之前,您需要了解接收者 (receiver) 是什麼。 接收者是函數被呼叫的對象。換句話說,接收者是資訊共享的目標。

寄件者與接收者的範例

在此範例中,main() 函數呼叫了 .first() 函數來回傳列表中第一個元素。 .first() 函數是針對 readOnlyShapes 變數呼叫的,因此 readOnlyShapes 變數是接收者。

要建立擴展函數,請撰寫您要擴展的類別名稱,後跟一個 . 和您的函數名稱。然後繼續撰寫函數宣告的其餘部分,包括其引數和回傳類型。

例如:

kotlin
fun String.bold(): String = "<b>$this</b>"

fun main() {
    // "hello" 是接收者
    println("hello".bold())
    // <b>hello</b>
}

在此範例中:

  • String 是被擴展的類別,也稱為接收者類型。
  • bold 是擴展函數的名稱。
  • .bold() 擴展函數的回傳類型是 String
  • "hello",一個 String 的實例,是接收者物件。
  • 接收者在函數體內部透過 關鍵字this 來存取。
  • 字串模板 ($this) 用來存取 this 的值。
  • .bold() 擴展函數接收一個字串並將其包裝在 <b> HTML 元素中,以顯示粗體文字。

擴展導向設計

您可以將擴展函數定義在任何位置,這使您能夠建立擴展導向設計。這些設計將核心功能與有用但非必要的功能分開,使您的程式碼更易於閱讀和維護。

一個很好的例子是來自 Ktor 函式庫的 HttpClient 類別,它有助於執行網路請求。其核心功能是單一的 request() 函數,它接收 HTTP 請求所需的所有資訊:

kotlin
class HttpClient {
    fun request(method: String, url: String, headers: Map<String, String>): HttpResponse {
        // 網路程式碼
    }
}

在實踐中,最受歡迎的 HTTP 請求是 GET 或 POST 請求。對於函式庫來說,為這些常見用例提供較短的名稱是合理的。然而,這些不需要撰寫新的網路程式碼,只需要特定的 request 呼叫。換句話說,它們是定義為單獨的 .get().post() 擴展函數的完美候選者:

kotlin
fun HttpClient.get(url: String): HttpResponse = request("GET", url, emptyMap())
fun HttpClient.post(url: String): HttpResponse = request("POST", url, emptyMap())

這些 .get().post() 函數會呼叫 request() 函數並帶有正確的 HTTP 方法,因此您不必這麼做。它們簡化了您的程式碼並使其更易於理解:

kotlin
class HttpClient {
    fun request(method: String, url: String, headers: Map<String, String>): HttpResponse {
        println("Requesting $method to $url with headers: $headers")
        return HttpResponse("Response from $url")
    }
}

fun HttpClient.get(url: String): HttpResponse = request("GET", url, emptyMap())

fun main() {
    val client = HttpClient()

    // 直接使用 request() 進行 GET 請求
    val getResponseWithMember = client.request("GET", "https://example.com", emptyMap())

    // 使用 get() 擴展函數進行 GET 請求
    val getResponseWithExtension = client.get("https://example.com")
}

這種擴展導向的方法在 Kotlin 的 標準函式庫 和其他函式庫中被廣泛使用。例如,String 類別有許多 擴展函數 可幫助您處理字串。

有關擴展函數的更多資訊,請參閱 擴展

練習

練習 1

撰寫一個名為 isPositive 的擴展函數,它接收一個整數並檢查它是否為正數。

kotlin
fun Int.// 在此撰寫您的程式碼

fun main() {
    println(1.isPositive())
    // true
}
範例解答
kotlin
fun Int.isPositive(): Boolean = this > 0

fun main() {
    println(1.isPositive())
    // true
}
練習 2

撰寫一個名為 toLowercaseString 的擴展函數,它接收一個字串並回傳其小寫版本。

提示
使用 String 類型的 .lowercase() 函數。
kotlin
fun // 在此撰寫您的程式碼

fun main() {
    println("Hello World!".toLowercaseString())
    // hello world!
}
範例解答
kotlin
fun String.toLowercaseString(): String = this.lowercase()

fun main() {
    println("Hello World!".toLowercaseString())
    // hello world!
}