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
x
refers 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".