1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

レシーバ付き関数リテラルを使用した関数についてやっと理解できた(はず)

Last updated at Posted at 2023-12-24

はじめに

業務でKotlinを使用していますが、Kotlin Koansでレシーバ付き関数リテラルの記述を見て「?」となったので理解できるまで調べました。
未来の自分が見ても振り返れるようにまとめます。

?となったコード

以下のコードです。

関数定義
fun buildString(build: StringBuilder.() -> Unit): String {
    val stringBuilder = StringBuilder()
    stringBuilder.build()
    return stringBuilder.toString()
}

引数でレシーバ付き関数リテラルを使用しています(build: StringBuilder.() -> Unitの部分)。
上記関数を使用する場合、以下のように使用します。

使用例
val s = buildString {
    this.append("Numbers: ")
    for (i in 1..3) {
        // 'this' can be omitted
        append(i)
    }
}

最初はこのコードを見た時点で何が起こっているか理解できませんでした。

理解できなかった点

buildStringの定義内でなぜbuild()とできるのか?

理由は以下の通りです。

  • buildの型がStringBuilder.() -> Unitであり、関数なのでbuild()と呼び出しができる
  • () -> Unitの部分は、引数なし、戻り値なしの関数
  • StringBuilder.()の部分は、StringBuilderの引数なしの拡張関数

上記の理解ができたことでこの疑問は解決しました。

使用時の記述が理解できない

buildString {}の中身の処理は理解できますが、なぜbuildString {}の記載のみでいいのかが理解できませんでした。

これは、StringBuilderの引数なしの拡張関数の実装だったことがわかったことで納得できました。
つまり、buildString使用時に実装を記述しているということでした。
なのでbuildString {}{}内の実装がbuildStringの関数定義内で使用され、結果がsに代入されていることになります。

上記から、共通処理はレシーバ付き関数リテラルを引数に持つ関数で記載し、固有の処理は呼び出し時に記載する、といった使用方法ができると理解しました。

終わりに

今回記載したことが理解できたことで、レシーバ付き関数リテラルの使い所も理解できたと思っています。。。

参考資料

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?