Skip to content

Intermediate: 拡張関数

この章では、コードをより簡潔で読みやすくするKotlinの特殊な関数について説明します。これらの関数が、効率的な設計パターンを使用してプロジェクトを次のレベルに引き上げるのにどのように役立つかを学びます。

拡張関数

ソフトウェア開発では、元のソースコードを変更せずにプログラムの動作を変更する必要があることがよくあります。たとえば、プロジェクトでサードパーティライブラリのクラスに追加の機能を持たせたい場合があります。

拡張関数を追加してクラスを拡張することで、これを実現できます。拡張関数は、クラスのメンバー関数を呼び出すのと同じ方法で、ピリオド (.) を使用して呼び出します。

拡張関数の完全な構文を導入する前に、レシーバーとは何かを理解する必要があります。レシーバーとは、関数が呼び出される対象のことです。言い換えれば、レシーバーは情報が共有される場所、または共有される相手です。

送信者と受信者の例

この例では、main()関数がリストの最初の要素を返す.first()関数を呼び出しています。 .first()関数はreadOnlyShapes変数に対して呼び出されるため、readOnlyShapes変数がレシーバーです。

拡張関数を作成するには、拡張したいクラス名の後に.を記述し、その後に自分の関数名を記述します。その後に、引数や戻り値の型を含む残りの関数宣言を続けます。

例:

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

fun main() {
    // "hello" is the receiver
    println("hello".bold())
    // <b>hello</b>
}

この例では:

  • Stringは拡張されたクラスです。
  • boldは拡張関数の名前です。
  • .bold()拡張関数の戻り値の型はStringです。
  • Stringのインスタンスである"hello"はレシーバーです。
  • レシーバーは、本体内でキーワード thisによってアクセスされます。
  • 文字列テンプレート ( ) を使用して、this`の値にアクセスします。
  • .bold()拡張関数は、文字列を受け取り、太字テキスト用の<b> HTML要素でそれを返します。

拡張指向設計

拡張関数はどこでも定義できるため、拡張指向設計を作成できます。これらの設計は、コア機能を有用だが不可欠ではない機能から分離し、コードの読みやすさとメンテナンス性を向上させます。

良い例は、ネットワークリクエストの実行に役立つKtorライブラリのHttpClientクラスです。その機能のコアは、HTTPリクエストに必要なすべての情報を受け取る単一の関数request()です。

kotlin
class HttpClient {
    fun request(method: String, url: String, headers: Map<String, String>): HttpResponse {
        // Network code
    }
}

実際には、最も一般的な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()関数は、正しいHTTPメソッドでrequest()関数を呼び出すため、自分で呼び出す必要はありません。これらはコードを簡素化し、理解しやすくします。

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()

    // Making a GET request using request() directly
    val getResponseWithMember = client.request("GET", "https://example.com", emptyMap())

    // Making a GET request using the get() extension function
    val getResponseWithExtension = client.get("https://example.com")
}

この拡張指向アプローチは、Kotlinの標準ライブラリやその他のライブラリで広く使用されています。たとえば、Stringクラスには、文字列を操作するのに役立つ多くの拡張関数があります。

拡張関数の詳細については、拡張を参照してください。

練習

演習1

整数を受け取り、それが正であるかをチェックするisPositiveという拡張関数を記述してください。

kotlin
fun Int.// Write your code here

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 // Write your code here

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

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