这篇文章是在Kotlin协程的时候思考写下的。
在Kotlin中,创建一个协程,需要调用createCoroutine函数,有两个函数叫这个名字,其中之一函数的声明是这样的。
public fun <R, T> (suspend R.() -> T).createCoroutine(
receiver: R,
completion: Continuation<T>
): Continuation<Unit> = SafeContinuation(createCoroutineUnchecked(receiver, completion), COROUTINE_SUSPENDED)
我们注意到 createCoroutine 是一个扩展函数,谁的扩展函数呢?suspend R.()->T 这个匿名函数的扩展函数。
很神奇,为什么一个函数能有扩展函数呢?
因为Kotlin中的匿名函数实际上也就是一个类,所以匿名函数当然可以有扩展函
所以这样写是完全没问题的,但是调用的位置就要注意了,必须是函数对象才能调用,下面的写法就无法调用到test1函数。
只能把函数转变为对象才可以调用
然后我们进入下一个问题,泛型的扩展函数的扩展函数是什么东西,我们把test1函数改一下,
fun <T> (T.() -> Unit).test1(): Unit {
}
这样,我们应该怎么调用这个函数呢,逆向思考,只有函数对象才能有扩展函数,那么T.()->Unit就应该是一个函数对象,而::doFunction就是一个对象啊,我们试一下。
果然没问题。但是泛型并没有发挥作用,因为doFunction函数是在调用的位置,才由函数转化为对象的,在doFuncion还是一个函数的时候,并不知道它会变成谁的匿名函数,所以完全跟泛型不搭边了,那这个位置加个泛型到底由什么用呢?往下分析。
扩展函数有一个重要的属性,就是可以调用到其Reciver类中对外公开的属性和方法。给扩展函数加一个泛型,就是为了调用到泛型内部的公开属性和方法。
我们换个写法,模仿一下KT的协程里面场景。
先写个接口,模仿KT协程里面的 Coroutine类
再写个类,模拟协程调用的位置
我们发现,有泛型的方法,可以获取到一个this。 因为上一个Demo中doFunction不是一个匿名函数,且本来就是MainActivity类的成员,所以即使不把扩展函数成泛型写法,也可以获取到MainActivity的成员,所以看不出来差别。
但是在下面这个Demo中,由于block函数成为了泛型T ,也就是TestInterface的扩展函数,所以可以调用到TestInterface的这个This,而没有泛型的方法则无法调用到。