Take the following code sample:
class Food(var size: Int, val doSomething: () -> Unit) {
init {
var t = 0
}
operator fun invoke() {
doSomething()
}
}
var x = ::Food
x.invoke(10) {
var x = 1
}
When x.invoke(10) is called, the init in Food is called. But the invoke function is not called. This seems odd. What is ::Food referencing and what exactly is x.invoke calling if the actual invoke function is not even being called?
It appears that x refers to the constructor. You can call the constructor by just calling:
x(10) {}
But including the .invoke does nothing. The constructor still gets called (and hence the init) but the invoke function itself does nothing. Not even sure why this is even allowed.
I have a feeling that .invoke is calling Kotlin's own built-in invoke function and NOT the operator function that is in the class.
CodePudding user response:
the invoke function can be called by writing () behind an instance of the class. so simply writing
x.invoke(10) {
println("test")
}()
could work for your example and prints "test". Or this for example
val s = x.invoke(10) {
println("test")
}
s()
s()
prints test twice
CodePudding user response:
It appears that
xrefers to the constructor.
Your observation is correct. x(10) {} and x.invoke(10) {} are indeed the same. The former is just a syntactic sugar for the latter, in the same way that 1 1 is just a syntactic sugar for 1.plus(1).
In fact, this is the whole point of the invoke operator, and the reason why you can directly call function/constructor references. If x has declared an invoke(...) operator, then x(...) means x.invoke(...).
::Food, being a reference to the constructor of Food, is of type KFunction2<Int, () -> Unit, Food>. This type is specified to have a invoke() operator that takes an Int and () -> Unit, and returns a Food. When you do x(10) {} or x.invoke(10) {}, you are calling that invoke operator, not the one in Food.
To call the invoke in Food, you need an instance of Food, which is exactly what x(10) {} or x.invoke(10) {} returns.
x(10) {
println("foo")
}.invoke()
// or
x(10) {
println("foo")
}()
Either of the above would print "foo".
