Kotlin's :: syntax and higher-order functions encounter pitfalls

Everyone knows that Kotlin has higher-order functions, and the function type of each function consists of the function's formal parameter list, -> and return value type. for example:

fun pow(base : Int, expo : Int) : String {}
// 使用::将函数名称赋值给变量
var myfun : (Int, Int)->String = ::pow 

Just like data types, function types can be used to define variables, function parameter types, and function return value types, like C function pointers.

Recently, I encountered a pit in project development. The brief code is as follows:

object A {
    data class Job(private val foo: WeakReference<(Int)->Unit>)
    private val queue = Queue<Job>()
    fun doWork() {
        // ...
        job = queue.get(0)
        job.get()?.invoke(1)
    }
    
    fun addJob(job: Job) {
        queue.add(job)
    }   
}

class B() {
    fun add(i : Int) {
    } 
    fun foo() {
        A.addJob(Job(WeakReference(::add)))
    }
}

Both A and B are in a foreground Activity C. At some point, A's doWork method will be triggered, and it will be called back to B's add method. This is the background. During the development process, it was found that the output of job.get() was always empty. It stands to reason that C holds B, and the add function is in B. This reference chain should be fine. Later, after compiling it into bytecode, I looked at it and it became something like this:

class A {
    class Job{
        private final WeakReference<Function1<Int, Unit>> callback;
    }
    //...
}
class B {
    public void foo() {
        A.addJob(Job(WeakReference(new D(this))))
    }
}

class D{
    private B b;
    D(B b) {
        this.b = b
    }
    public void foo1(int i){
        b.add(i)
    }
}

The object passed to WeakReference turned out to be an anonymous object. No one references this anonymous object, and it must be recycled immediately.

insert image description here

Then change B to the following:

class B() {
    private val add = { i: Int ->
        //...
    }
    fun foo() {
        A.addJob(Job(WeakReference(add)))
    }
}

Look at the compiled one. At this time, what is passed to WeakReference is a member variable.
insert image description here
insert image description here
This callback is equivalent to a member function of B
I still don't know enough about the new grammar to encounter this pit. . .

Guess you like

Origin blog.csdn.net/aa642531/article/details/100712667