Kotlinのレシーバー
Kotlinのレシーバー(Receiver)
Kotlinの「レシーバー(Receiver)」とは、関数が呼び出される対象となるオブジェクトのことです。
特定のオブジェクトのコンテキスト内で関数を実行することを可能にする概念で、特に拡張関数やスコープ関数で重要になります。
レシーバーの種類
1. ディスパッチレシーバー(Dispatch Receiver)
クラスのインスタンスそのものです。
クラスのメンバー関数(メソッド)を呼び出すときに、その関数が属するオブジェクトがディスパッチレシーバーです。
class MyClass {
fun greet() {
println("Hello from MyClass!")
}
}
fun main() {
val myObject = MyClass()
myObject.greet() // myObject がディスパッチレシーバー
}
この greet
関数の中で this
と書くと、myObject
のインスタンスを指します。
2. 拡張レシーバー(Extension Receiver)
拡張関数が拡張する型(クラス)のインスタンスです。
拡張関数は、既存のクラスに新しい関数を追加できますが、その内部では拡張対象のインスタンスをレシーバーとして受け取ります。
fun String.sayHello() {
println("Hello, $this!") // $this は拡張レシーバー(Stringのインスタンス)
}
fun main() {
"World".sayHello() // "World" が拡張レシーバー
val name = "Alice"
name.sayHello() // name が拡張レシーバー
}
この sayHello
関数の中で this
と書くと、拡張対象の String
のインスタンスを指します。
なぜレシーバーが重要なのか?
-
コンテキストの提供
→ 関数がどのオブジェクトのデータや振る舞いを操作するのか、その「文脈」を提供する。 -
コードの可読性と表現力
→ 拡張関数により、既存クラスを修正せずに新しい機能を追加できる。
→ 例:string.isNullOrEmpty()
-
スコープ関数(apply, with, run, also, let など)
→ 特定のオブジェクトのコンテキスト内で複数の操作を行える。冗長なコードを削減し、可読性を向上。 -
DSL(ドメイン固有言語)の構築
→ レシーバー付きラムダ(Lambda with Receiver)により、オブジェクトの内部にいるかのように自然な構文で記述できる。
スコープ関数とレシーバー
スコープ関数は、レシーバーの概念を活用しています。
apply
と with
ラムダのレシーバーとしてオブジェクト自身を渡す。
ラムダ内で this
を使うと、そのオブジェクトを参照する。
data class Person(var name: String, var age: Int)
fun main() {
val person = Person("Alice", 30).apply {
// this は Person オブジェクト
this.age = 31 // this は省略可能
name = "Alicia"
}
println(person) // Person(name=Alicia, age=31)
}
let
と also
ラムダの引数としてオブジェクト自身を渡す。
ラムダ内で it
を使うと、そのオブジェクトを参照する。
fun main() {
val numbers = mutableListOf("one", "two", "three")
val firstAndSecond = numbers.also {
// it は mutableListOf("one", "two", "three")
println("The list elements before adding new one: $it")
it.add("four")
}
println(firstAndSecond) // [one, two, three, four]
}