この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
毎日Kotlinシリーズです。
このシリーズを初めての方はこちらです。「毎日Kotlin」はじめました | Developers.IO
問題
invokable()()こんな感じで呼び出すにはどうしたらいいでしょうか。
Objects with invoke() method can be invoked as a function.
You can add invoke extension for any class, but it's better not to overuse it:
fun Int.invoke() { println(this) }
1() //huh?..
Implement the function Invokable.invoke() so it would count a number of invocations.
class Invokable {
var numberOfInvocations: Int = 0
private set
operator fun invoke(): Invokable {
TODO()
}
}
fun invokeTwice(invokable: Invokable) = invokable()()
狙い
ここで考えて欲しい問題の意図はなんだろうか?
invokeはよく使うoperatorです。カッコイイ文法を作りたい人御用達です。invokeは呼び出しに省略形が存在します。operator系は便利なのですが暗記の要素も多いので覚えよう。
解答例
class Invokable {
var numberOfInvocations: Int = 0
private set
operator fun invoke(): Invokable {
numberOfInvocations += 1
return this
}
}
fun invokeTwice(invokable: Invokable) = invokable()()
まずはシンプルにinvokeを省略無しと有りで呼び出しみましょう。
val invokable = Invokable()
invokable.invoke() // 省略なし
invokable() // 省略あり
invokeの省略形はinvokeを省略して()だけで呼び出しができます。またinvokeは引数と型は好きに定義できます。今回の場合はoperator fun invoke(): Invokableで、引数なしで、返り値がInvokableになっています。invokable()()を省略しないで書いてみるとinvokable.invoke().invoke()。単純ですね。
補足
invokeは引数と型は好きに定義できるのでこんな感じのもできます。
val sum = Sum()
print(sum(1)(2)(3).sum)
print(sum(1,2))
class Sum {
var sum = 0
private set
operator fun invoke(x: Int): Sum {
sum += x
return this
}
operator fun invoke(x: Int, y: Int): Int {
return x + y
}
}
あとがき
Day22.でまたお会いしましょう。