區分 Kotlin 中的擴充套件函式

David Mbochi Njonge 2023年1月30日 2022年6月21日
  1. 在 Kotlin 中建立擴充套件函式
  2. 在 Kotlin 中使用 Lambda 函式和擴充套件函式
  3. 在 Kotlin 中使用 let() 擴充套件函式
  4. 在 Kotlin 中使用 also() 擴充套件函式
  5. 在 Kotlin 中使用 apply() 擴充套件函式
  6. 在 Kotlin 中使用 takeIf() 擴充套件函式
  7. 在 Kotlin 中使用 takeUnless() 擴充套件函式
  8. まとめ
區分 Kotlin 中的擴充套件函式

在物件導向程式設計中,我們學習了繼承、封裝、抽象和多型的概念,但這些不足以以靈活、可重用和可維護的方式構建我們的應用程式。

設計模式,在設計原則和 OOP 概念的幫助下,提供瞭解決方案來解決常見的設計問題。一種與我們將在本教程中介紹的非常相似的設計模式是裝飾器設計模式。

裝飾器設計模式允許我們嚮應用程式新增功能,而無需從另一個類擴充套件。在 Kotlin 中,我們可以通過使用 Kotlin 擴充套件函式來實現相同的功能設計模式。

Kotlin 中的擴充套件函式向一個類新增功能,而無需從另一個類擴充套件或使用裝飾器設計模式。在幕後,擴充套件函式可以是泛型的,可以使用 lambda 函式來實現我們提到的功能。

在本教程中,我們將深入瞭解每個擴充套件函式,併為每個函式提供一個示例。本文介紹的擴充套件函式包括:apply()also()let()takeIf()takeUnless()

在 Kotlin 中建立擴充套件函式

要建立擴充套件函式,請定義要新增功能的型別,例如字串、數字或類,並使用點運算子定義委託功能的方法。定義擴充套件函式的返回型別,最後在同一行實現方法的邏輯。

轉到 Intellij 程式碼編輯器並建立一個名為 extension-exercise 的新專案。在 src 下,建立資料夾結構 com.extension

extension 資料夾下建立一個 Main.kt 檔案並貼上以下程式碼。

package com.extension

fun Number.isGreaterThanTen(): Boolean = this.toInt() > 10;

fun main() {
    val  num = 100;
    println(num.isGreaterThanTen());
}

在上面的程式碼中,我們在 Number 型別上定義了一個名為 isGreaterThanTen() 的擴充套件函式,它檢查一個數字是否大於 10 並返回一個布林值。

如果你從此時開始呼叫任何 number 型別的變數,你將可以訪問 isGreaterThanTen() 方法,如上面的 main 方法所示。

請注意,當你執行上述程式時,會在控制檯中記錄布林值 true

true

在 Kotlin 中使用 Lambda 函式和擴充套件函式

在幕後,一個 lambda 函式可以定義為一個只包含一個方法的介面。lambda 函式匿名傳遞給具體函式,無需指定函式名稱,然後使用箭頭符號定義返回型別。

建立另一個檔案並將之前的程式碼移動到該檔案中。將以下示例複製並貼上到空的 Main.kt 檔案中。

package com.extension

fun Number.isGreaterThanTen(block: (Number) -> Boolean): Boolean = block(this);

fun main() {
    val num = 100;
    println(num.isGreaterThanTen { number ->
        number.toInt() > 10
    })

}

在上面的程式碼中,我們定義了一個名為 isGreaterThanTen() 的擴充套件函式,它接受一個 lambda 函式作為引數並返回一個布林值。

我們命名為 block 的 lambda 函式接受 Number 型別的引數並返回一個布林值。lambda 函式返回的這個布林值被委託給擴充套件函式。

與前面的示例相比,我們在對主函式內的任何 Number 型別的變數呼叫 isGreaterThanTen() 後定義擴充套件函式的邏輯。

執行上面的程式碼,觀察我們得到的結果和前面的例子一樣。輸出如下圖所示。

true

在 Kotlin 中使用 let() 擴充套件函式

將之前的程式碼移動到我們建立的新檔案中,並將以下程式碼貼上到 Main.kt 檔案中。

package com.extension

inline fun <T, R> T.let(block: (T) -> R): R = block(this);

fun  main(){
    val num = 10;
    val result = num.let { number -> number.toString() }
    println(result);
    println(result::class.java.typeName);
}

let() 函式是使用泛型定義的,這意味著它可以使用任何型別。呼叫 let() 函式的物件作為 lambda 函式的引數傳遞。

lambda 函式在 let() 函式內部定義,並返回與作為引數傳遞的物件不同的物件。

由於 let() 函式返回的值與 lambda 函式返回的函式相同,我們將 lambda 函式返回值委託給 let() 函式。

在 main 方法中,我們定義了一個 Number 型別的變數,並呼叫我們的擴充套件函式來返回數字的字串表示形式。

然後,我們將返回的值及其型別記錄到控制檯,以驗證擴充套件功能是否按要求工作。請注意,傳遞給擴充套件函式的型別是數字,但返回的值是字串,如下所示。

10
java.lang.String

在 Kotlin 中使用 also() 擴充套件函式

將之前的程式碼移動到我們建立的新檔案中,並將以下程式碼貼上到空的 Main.kt 檔案中。

package com.extension

inline fun <T> T.also(block: (T) -> Unit): T {block(this); return  this}

fun main(){
    val  num = 10;
    num.also {i ->
        println(i == 10)
    }
}

呼叫 also() 擴充套件函式的物件作為 lambda 函式的引數傳遞。lambda 函式被定義為擴充套件函式的引數,並且不返回任何通常由 Unit 表示的值。

also() 函式返回你正在使用的當前變數,該變數被委託給 lambda 函式以進行進一步計算。在 main 函式中,我們定義了一個 Number 型別的變數,委託給 lambda 函式來檢查值是否等於 10。

執行程式碼並注意它返回一個真值,如下所示。

true

在 Kotlin 中使用 apply() 擴充套件函式

將之前的程式碼移動到我們建立的新檔案中,並將以下程式碼貼上到空的 Main.kt 檔案中。

package com.extension

inline fun <T> T.apply(block: T.() -> Unit): T {block(); return this}

fun main(){
    val num = 10;
    num.apply {
        println(toDouble());
    }
}

呼叫 apply() 擴充套件函式的物件作為該物件的方法呼叫傳遞給 lambda 函式的引數。lambda 函式沒有返回值。

該定義意味著我們不必使用型別的物件來呼叫方法,因為 lambda 函式會處理該功能。在這種情況下,我們只需要從一個型別中呼叫我們需要的方法。

在主函式中,我們定義了一個 Number 型別的變數,並使用 apply() 方法,我們通過呼叫 toDouble() 方法將 Number 轉換為 Double。請注意,沒有使用對物件的引用來呼叫 toDouble() 方法。

執行上面的程式碼,注意記錄到控制檯的值是 Double,如下圖。

10.0

在 Kotlin 中使用 takeIf() 擴充套件函式

將之前的程式碼移動到我們建立的新檔案中,並將以下程式碼貼上到空的 Main.kt 檔案中。

package com.extension

inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? = if (predicate(this)) this else null

fun main() {
    val  num = 10;
    println(num.takeIf { i ->
        i.plus(10) < 30
    })
}

呼叫 takeIf() 擴充套件函式的物件作為 lambda 函式的引數傳遞。lambda 函式作為此方法的引數傳遞,並返回一個布林值。

僅當 lambda 表示式的條件計算為 true 時,擴充套件函式才返回撥用物件。否則,它返回一個 null 值。

在主函式中,我們定義了一個 Number 型別的值,它使用 takeIf() 來確定這個數字加 10 是否小於 30。如果條件評估為真,則返回值 10;否則,返回一個 null 值。

執行上面的程式碼,注意 lambda 表示式的計算結果為 true,並返回值 10,如下所示。

10

在 Kotlin 中使用 takeUnless() 擴充套件函式

將之前的程式碼移動到我們建立的新檔案中,然後將以下程式碼複製並貼上到空的 Main.kt 檔案中。

package com.extension

inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? = if (!predicate(this)) this else null

fun main() {
    val num = 10;
    println(num.takeUnless { i ->
        i.plus(10) < 30
    })
}

呼叫 takeUnless() 擴充套件函式的物件作為 lambda 函式的引數傳遞。lambda 函式在此方法中定義並返回一個布林值。

takeIf()takeUnless() 之間的區別在於,此示例僅在 lambda 表示式的計算結果為 false 時返回一個值。這意味著擴充套件函式返回的值是 lambda 函式返回的布林函式的倒數。

在 main 方法中,我們定義了與上面相同的示例,但請注意,此示例將返回 null,因為 lambda 函式的計算結果為 true,它被反轉為 false

null

まとめ

本教程教我們如何使用擴充套件函式在 Kotlin 中新增功能。涵蓋的擴充套件函式包括:使用 let()also()apply()takeIf()takeUnless()

請注意,這些擴充套件函式已經在 Kotlin API 中定義,你不必像我們在本教程中所做的那樣定義它們。

David Mbochi Njonge avatar David Mbochi Njonge avatar

David is a back end developer with a major in computer science. He loves to solve problems using technology, learning new things, and making new friends. David is currently a technical writer who enjoys making hard concepts easier for other developers to understand and his work has been published on multiple sites.

LinkedIn GitHub