はじめに
公式の問題集「Kotlin Koans」を解きながらKotlinを学習します。
過去記事はこちら
- Introduction
- Classes
- Conventions
- Collections
- Properties
問題
Function literals with receiver
関数リテラルについて、レシーバを使って学びます。
isEven
とisOdd
を拡張関数として呼び出せる値として宣言することができます。
コードの中で宣言を完成させましょう。
fun task(): List<Boolean> {
val isEven: Int.() -> Boolean = { TODO() }
val isOdd: Int.() -> Boolean = { TODO() }
return listOf(42.isOdd(), 239.isOdd(), 294823098.isEven())
}
問題のポイント
Function literals with receiver
A.(B) -> C
のようなreceiverを持つ関数型は,関数リテラルの特殊な形式であるreceiver付き関数リテラルでインスタンス化することができます。
前述の通り、Kotlinではreceiverを持つ関数型のインスタンスを、receiverオブジェクトを提供しながら呼び出す機能があります。
関数リテラルの本体内部では、呼び出しに渡されたReceiverオブジェクトは暗黙のthis
となり、追加の修飾子なしにそのReceiverオブジェクトのメンバーにアクセスしたり、this
式を使ってReceiverオブジェクトにアクセスしたりできるようになります。
この動作は拡張関数と同様で、拡張関数も関数本体の内部で受信機オブジェクトのメンバにアクセスすることができます。
以下は、関数リテラルの型に Receiver を指定し、Receiver オブジェクトに対して plus
を呼び出した例です。
val sum: Int.(Int) -> Int = { other -> plus(other) }
匿名関数の構文では、関数リテラルのレシーバー型を直接指定することができます。
これは、関数型の変数をreceiverで宣言しておき、後でそれを使用する必要がある場合に便利です。
val sum = fun Int.(other: Int): Int = this + other
ラムダ式は、文脈からreceiverの型が推測できる場合、receiverを持つ関数リテラルとして使用することができます。
最も重要な使用例として、タイプセーフビルダがあります。
解答例
fun task(): List<Boolean> {
val isEven: Int.() -> Boolean = { this % 2 == 0 }
val isOdd: Int.() -> Boolean = { this % 2 != 0 }
return listOf(42.isOdd(), 239.isOdd(), 294823098.isEven())
}