[毎日Kotlin] Day21. Invoke

2018.02.13

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

毎日Kotlinシリーズです。

このシリーズを初めての方はこちらです。「毎日Kotlin」はじめました | Developers.IO

問題

Invoke | Try Kotlin

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.でまたお会いしましょう。